Your Digital Media Has Never Looked So Good

 
belltown
Topic Author
Posts: 1465
Joined: Thu Dec 09, 2010 1:43 pm
Contact:

How to play audio content in SDK videoplayer

Tue Jul 31, 2012 12:11 pm

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.
https://github.com/belltown/
 
bandal
Posts: 260
Joined: Sat Oct 15, 2011 2:17 pm

Re: How to play audio content in SDK videoplayer

Tue Jul 31, 2012 12:20 pm

I found this out by accident about a week ago. At least the answer is simple.
DA
 
Gary1980Arb
Posts: 9
Joined: Fri Sep 14, 2012 4:45 pm

Re: How to play audio content in SDK videoplayer

Sun Sep 16, 2012 2:44 pm

Bandal, you are Heaven Sent !!!

This is exactly what I needed for my Channel as well!!

Bless you, Bless You !!!

I believe you are the most helpful person in this forum!!
 
bandal
Posts: 260
Joined: Sat Oct 15, 2011 2:17 pm

Re: How to play audio content in SDK videoplayer

Sun Sep 16, 2012 5:11 pm

You can also play Live Internet Streams by placing in the streamurl the actual link and Port with the slash or / at the end. Here is one to try. Set StreamFormat to mp3.
<streamUrl>http://67.228.150.184:9015/</streamUrl>

I was able to get it with a pc program called UrlGetter and play a Shoutcast Stream in VLC while UrlGetter is running and you can find the address and port number.
Credit to belltown.

Thanks,

DA
Last edited by bandal on Tue Sep 18, 2012 12:48 pm, edited 1 time in total.
 
destruk
Posts: 2720
Joined: Sat Dec 18, 2010 4:58 pm

Re: How to play audio content in SDK videoplayer

Sun Sep 16, 2012 5:32 pm

See, I don't understand that - the need for a 'ripper' program for Shoutcast?
That makes about as much sense as someone paying for a screenshot program because they can't be troubled to use printscreen and paste, lol.

All the currently broadcasting shoutcast servers are listed here: http://www.shoutcast.com/radio/List
You can search for whatever you want to listen to - when it shows up in the list, right click the name and "save link as" which saves a .PLS file to your hard drive.
Open it in notepad and there is the URL you need in plain text right there.
 
bandal
Posts: 260
Joined: Sat Oct 15, 2011 2:17 pm

Re: How to play audio content in SDK videoplayer

Sun Sep 16, 2012 5:53 pm

Thanks, I knew there must be an easier way. Just never took the time to get this far as I needed it only 2 times. Thanks for the info looks way easier now.
DA
 
agmark
Posts: 142
Joined: Thu Nov 10, 2011 8:29 am

Re: How to play audio content in SDK videoplayer

Tue Sep 18, 2012 9:39 am

Gary1980Arb wrote:
Bandal, you are Heaven Sent !!!

This is exactly what I needed for my Channel as well!!

Bless you, Bless You !!!

I believe you are the most helpful person in this forum!!


I believe you meant to thank belltown and I couldn't agree more. Belltown continues to be a great asset to this forum. My thanks as well!
 
bandal
Posts: 260
Joined: Sat Oct 15, 2011 2:17 pm

Re: How to play audio content in SDK videoplayer

Tue Sep 18, 2012 12:49 pm

I agree.
 
Gary1980Arb
Posts: 9
Joined: Fri Sep 14, 2012 4:45 pm

Re: How to play audio content in SDK videoplayer

Wed Sep 19, 2012 4:08 pm

Thank you belltown !!
 
RobSMS
Posts: 72
Joined: Thu Jan 09, 2014 8:30 pm

Re: How to play audio content in SDK videoplayer

Wed Mar 11, 2015 3:19 pm

I implemented this code, but I have one bug I just can't figure out when playing a shoutcast/icecast stream.

On my Roku 2XD it sometimes buffers for up to 2 minutes, then starts playing fine. Occasionally it starts after 2 or 3 seconds.

I thought it was the shoutcast stream or my wireless connection, but then I tried it on my Roku 3 in a room that is farther away from my router and it worked fine every time.

Any ideas?
Need Apps Templates? Content Management for OTT/IPTV? Check me out @ http://rovidx.com
 
belltown
Topic Author
Posts: 1465
Joined: Thu Dec 09, 2010 1:43 pm
Contact:

Re: How to play audio content in SDK videoplayer

Wed Mar 11, 2015 5:08 pm

RobSMS wrote:
I implemented this code, but I have one bug I just can't figure out when playing a shoutcast/icecast stream.

On my Roku 2XD it sometimes buffers for up to 2 minutes, then starts playing fine. Occasionally it starts after 2 or 3 seconds.

I thought it was the shoutcast stream or my wireless connection, but then I tried it on my Roku 3 in a room that is farther away from my router and it worked fine every time.

Any ideas?

It appears to be a long-standing bug in roAudioPlayer. I played around with various workarounds. What I'm currently doing is when I get the audio player's IsStreamStarted event, Pause then Resume the audio player, giving it a little Sleep time to think about it. It seems to work about 98% of the time. Something like this:

Sleep (350)
audio.Pause ()
Sleep (350)
audio.Resume ()


It doesn't seem very effective on the 3.1 firmware though. It still takes a while to buffer in that case. However, I'll change the text on the roSpringboardScreen's Play/Pause/Resume button to display a percentage showing how much buffering has been done, in response to the IsStatusMessage "startup progress" message so the user knows something is really happening (albeit slowly) rather than the channel having hung. I know this works on the Roku 2XS. I don't have a Roku 3, so I've no idea how it works (or if it's necessary) on that unit.
https://github.com/belltown/
 
RobSMS
Posts: 72
Joined: Thu Jan 09, 2014 8:30 pm

Re: How to play audio content in SDK videoplayer

Wed Mar 11, 2015 7:50 pm

Yeah, that seems to have fixed the issue. I like the idea of updating the buffer onscreen, thanks for the tips :)
Need Apps Templates? Content Management for OTT/IPTV? Check me out @ http://rovidx.com
 
LordDewi
Posts: 7
Joined: Sun Feb 01, 2015 10:09 pm

Re: How to play audio content in SDK videoplayer

Sat Mar 28, 2015 11:31 pm

Thank you @belltown for posting this. I wish I'd found this a few months ago. I actually wound up using this method for the channels I've been working on accidentally. I was trying to create audio channels using RSS feeds and the MRSS example only used video samples. After trying to modify the example Audio Player code, which uses roAudioPlayer, I just changed the <streamformat> in the videoplayer to mp3 and it worked and I was easily able to pull in an RSS feed to fill it.

I didn't change the appDetailScreen so I'll definitely look into that as currently it plays but shows no detail on the MP3 Audio stream, other than the title. I've seen that most Audio only channels play the audio while continuing to display the individual episode's screen, with my example it goes to the uiVideoScreen.brs screen and just shows the title and progress, which isn't horrible but with audio, I'd like to keep displaying the individual episode screen, NWM_MRSS.brs in my case. I'll look into the appDetailScreen.brs changes, although I don't see that in the MRSS example, but I'll look for it in the videoplayer example and play around with it.

Who is online

Users browsing this forum: No registered users and 5 guests