0

I'm developing a custom Roku channel and I need to use a livestream.com video stream from the following live stream event:

http://livestream.com/accounts/11222132/events/3665575

Using their json service I've been able to obtain an m3u8 stream. The stream works fine on iOS, Android, and Fire OS but I can't get it to work on Roku.

This code gets and attempts to play my stream:

Function displayVideo()
    print "Displaying video: "
    p = CreateObject("roMessagePort")
    video = CreateObject("roVideoScreen")
    video.setMessagePort(p)

    'bitrates  = [0]          ' 0 = no dots, adaptive bitrate
    'bitrates  = [348]    ' <500 Kbps = 1 dot
    'bitrates  = [664]    ' <800 Kbps = 2 dots
    'bitrates  = [996]    ' <1.1Mbps  = 3 dots
    'bitrates  = [2048]    ' >=1.1Mbps = 4 dots
    bitrates  = [0]    


    request = CreateObject("roUrlTransfer")
    request.SetUrl("http://livestream.com/api/accounts/11222132/events/3665575/viewing_info")
    jsonString = request.GetToString()
    myJson = ParseJSON(jsonString)
    theurl = myJson.streamInfo.m3u8_url
    urls = [theurl]
    print "the json url is:"
    print urls
    qualities = ["SD"]
    StreamFormat = "hls"
    title = "COACB TV 39"
    srt=""

    videoclip = CreateObject("roAssociativeArray")
    videoclip.StreamBitrates = bitrates
    videoclip.StreamUrls = urls
    videoclip.StreamQualities = qualities
    videoclip.StreamFormat = streamformat
    videoclip.Title = title
    print "srt = ";srt
    if srt <> invalid and srt <> "" then
        videoclip.SubtitleUrl = srt
    end if



    video.SetContent(videoclip)
    video.show()

    lastSavedPos   = 0
    statusInterval = 10 'position must change by more than this number of seconds before saving

    while true
        msg = wait(0, video.GetMessagePort())
        if type(msg) = "roVideoScreenEvent"
            if msg.isScreenClosed() then 'ScreenClosed event
                print "Closing video screen"
                exit while
            else if msg.isPlaybackPosition() then
                nowpos = msg.GetIndex()
                if nowpos > 10000

                end if
                if nowpos > 0
                    if abs(nowpos - lastSavedPos) > statusInterval
                        lastSavedPos = nowpos
                    end if
                end if
            else if msg.isRequestFailed()
                print "play failed: "; msg.GetMessage()
            else
                print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage()
            endif
        end if
    end while
End Function

in my console I get the following pertinent messages:

Displaying video:

the json url is:

http://api.new.livestream.com/accounts/11222132/events/3665575/broadcasts/92495453.m3u8?dw=100&hdnea=st=1436386598~exp=1436387498~acl=/i/11222132_3665575_bee34040_1@123585/*~hmac=dfacbbb090cc8df9435397d7c38d134be418756b3a00620297948eea35bedae7

srt =

Unknown event: 11 msg: Unspecified or invalid track path/url.

play failed:

Closing video screen

The error I'm getting indicates that the url is invalid and in fact if I give it a url value of "nothing honey", it gives me the same error. So if the url I am getting from this json is wrong.. then how is it wrong? It works on my other devices...

Ohiovr
  • 977
  • 1
  • 12
  • 22

1 Answers1

0

From a trail of internet breadcrumbs I discovered the answer from the following urls:

first this guy had the same problem I did:

http://forums.roku.com/viewtopic.php?f=34&t=83773&p=494689&hilit=livestream.com#p494689

he says he found the solution here: http://forums.roku.com/viewtopic.php?f=34&t=66537&p=425668&hilit=akamai

The second link didn't have a complete solution to my problem but it lacked only a few things which I've added onto the solution which I'll post further down. If you want to put a livestream.com live stream into a roku app you need to use their api to get a json object which contains an m3u8 stream. Ordinarily you could just send this url to a video player and it would work but it needs 2 cookies that it doesn't get automatically. In this case we have to extract them and then re attach them to another request.

'*************************************************************
'** displayLivestream()
'*************************************************************
Function displayLivestream ()
    request = CreateObject("roUrlTransfer")
    request.SetUrl("http://livestream.com/api/accounts/11222132/events/3665575/viewing_info")
    jsonString = request.GetToString()
    myJson = ParseJSON(jsonString)
    theurl = myJson.streamInfo.m3u8_url
   print theurl


   req = CreateObject("roUrlTransfer")
   req.SetPort(CreateObject("roMessagePort"))
   req.SetUrl(theurl)   
   req.EnableCookies()
   req.EnableFreshConnection(true)   
   if (req.AsyncGetToString())
      event = wait(30000, req.GetPort())
      if type(event) = "roUrlEvent"
         if (event.GetResponseCode() <> 200)
            'DisplayDialog("No Live Feed", "Please check back later.")
            print "roUrlEvent"
         endif

         headers = event.GetResponseHeadersArray()
      else if event = invalid
          print "AsyncGetToString timeout"
          req.AsyncCancel()
      else
          print "AsyncGetToString unknown event"
      endif
   endif


   Location = ""
   for each header in headers
      print header
      val = header.LookupCI("Set-Cookie")
      val2 = header.LookupCI("Location")
      if (val <> invalid)
         if (val.Left(5) = "hdntl")
            hdntl = val.Left(Instr(1,val,";")-1)
         endif
         if (val.Left(6) = "_alid_")
            alid = val.Left(Instr(1,val,";")-1)
         endif
      endif
      if (val2 <> invalid)
        Location = val2
      endif
   end for

   port = CreateObject("roMessagePort")
   screen = CreateObject("roVideoScreen")
   screen.SetMessagePort(port)
   screen.EnableCookies()  
   print "hdntl is:" 
   print hdntl
   print "alid is:" alid
   screen.AddHeader("Cookie",hdntl)
   screen.AddHeader("Cookie", alid)
   stream = {
      HDBranded: false
      IsHD: false
      StreamBitrates: [0]
      StreamUrls: [theurl]
      StreamQualities: [0]
      StreamFormat: "hls"
      Live: true
   }

   screen.SetContent(stream)
   screen.Show()
   lastSavedPos   = 0
   statusInterval = 10 'position must change by more than this number of seconds before saving

    while true
        msg = wait(0, screen.GetMessagePort())
        if type(msg) = "roVideoScreenEvent"
            if msg.isScreenClosed() then 'ScreenClosed event
                print "Closing video screen"
                exit while
            else if msg.isPlaybackPosition() then
                nowpos = msg.GetIndex()
                if nowpos > 10000

                end if
                if nowpos > 0
                    if abs(nowpos - lastSavedPos) > statusInterval
                        lastSavedPos = nowpos
                    end if
                end if
            else if msg.isRequestFailed()
                print "play failed: "; msg.GetMessage()
            else
                print "Unknown event: "; msg.GetType(); " msg: "; msg.GetMessage()
            endif
        end if
    end while
End Function
Ohiovr
  • 977
  • 1
  • 12
  • 22
  • BTW, edit out the cookie stuff now. Livestream changed something and now you don't have to do the weird obscure stuff with the cookies. The benefit is that now you can stream video to Samsung Smart TVs now. – Ohiovr Oct 15 '16 at 16:42