Infinite wait on roUrlTransfer object

Hi I am new to Roku development using brightscript. Please excuse me if im asking something stupid.

I am stuck in loading some images I got through roUrlTransfer object. This is what I am doing:

  1. Create seperate roUrlTransfer objects for each images (since I need it async) - call it ‘http’
  2. Saving the resul to tmp using AsyncGetToFile(temp_path)
  3. Pushing each http to imageTransfers array
  4. Finally, take each item from imageTransfers array and drawing bitmap out of it

I have a grid control which has 4 rows and 2 col (so initially 8 images will load). After that on each button_down_pressed event, i’m loading next row (2 items). But when I do

for each http in m.imageTransfers
msg = wait(0, http.GetPort())
if (type(msg) = “roUrlEvent”)


end if
end for

the code stops working at msg=wait(0, http.GetPort()). Its like an infinite wait. What am I doing wrong here? The initial 8 items in the grid is loading fine, and passing this code successfully. Please help :roll:

When I printed type of messages, most of them seems to be INVALID instead of roUrlEvent

But when i press down button again, im getting all 4 (2 from each row) roUrlEvent msgs.

Cant figure out why!

For what you want to do you are probably better
Off using rotexturemanager And do not use wait
But create a separate port for just your textures
and use port.getmessage In any case your async
Objects must stay on scope until it completes

Does texture manager supports legacy devices. I’m targeting roku2 as well. If it does, how will be the performance

I use it with the 2xd. Essentially does the same thing
As urltransfer. But it also returns an in memory bitmap
Reference to you. The transfer object writes to disk so
You have to load your bitmap from tmp. If I preload something
For use later on I use the transfer object. For loading directly
Into a grid I prefer the texturemanager. Performance wise they area out the same
With retrieving. Did notice along with someone else recently that
The transfer object my give slightly better download times on a single larger
Bitmap than the texturemanager. But for more than one on a component
Such as a grid during realtime scrolling definitely the manager
With the 2xd box i have to balance size, and number with performance
The textures arrive quick enough. But are disk and processor
Intensive. To see what I mean just start scrolling your home screens
Ok the 2 boxes. You will notice resistance and uneven movement
As the textures arrive during scrolling. If you open up a telnet
You can see that the manager or some equivalent is being used.

In the 4200 boxes it just absolutely impressive. No studdering at all

I tried roTextureManager. I have to load 20-25 or so images initially. It starts well, but after a while, most of the roTextureRequestEvent states are returining 4, which means Failed.

Is this a limitation of the texturemanager? Is there any work around?

20 -25 is well within reason for standard
Grid size textures. A failure code can mean
That your roTextureRequest may have gone
Out of scope. If you are requesting textures
asynchronously and not polling for returns
Within the same function , you need to
Make sure your texture requests are global to
Either an object or your application
If they go out of scope such as when creating them
Locally In a function and then exiting the
Function to listen somewhere else, they
Are removed from the function stack that
Created them and
Destroyed. This would generate a return of
4. Without seeing your code it is difficult
To determine where your problem is

This is what im doing with textureManager

in getBitmap function

  1. I am calling a function called sendRequest, which creates a roTextureReques object with the passed in url and send a RequestTexture request. As return, I am passing request object
  2. The request object is pushed to an imageTransfers array
  3. So, now I have imageTransfers array with all the roTextureRequest objects.
  4. then i loop through each items in the imagetransfers and calling a listening function. (here im using the same message port created at the time of request) and wait for the roTextureRequestEvent
  5. for first 12 items state =3, after that state=4.

The first 12 items remains in the scope. and I cant find any reason for the remaining items go out of the scope.

Something’s to remember

Create,push, send, receive, pop, destroy
Totally Recreate again when needed
Do not reuse a completed object
To re-request if removed from the manager
As a matter of fact it is better to save the
Bitmap than to save the request
Push onto an associative array list
With the objects. Id so you can find it
And pop it off the queue when returned

' This is an example of one way to manage a texture cache.  It is a very stripped down version
' of one that I use.  This version does not include the realtime populating of my grids that I have
' put out here.  I do have that if anyone is interested.  This version just includes the polling function
' that is used primarily for pseudo-async preloading.  But it demonstrates what is essentially needed to
' do this as well as an indicator of how fast the manager can be.  I have set up a test directory on my
' own content site.  The image files are small but I have acceptable results with images as large
' as 10 -  18 kb.  So for standard grid-sized poster images this should be very reasonable

' This was extracted from my channel and put together very quickly, and most of the error checking was removed.  
' But I believe I have included enough code to demonstrate a particular method that I use.  However some anomalies
' may exist, which if discovered I will be happy to fix

' My own experience with the manager is only about 4 months but I have learned a lot and have come to really appreciate
' the texture manager.  It works very well with my grids which I have redesigned to be fully integrated with
' my managers.  If anyone can contribute and make it better we can all benefit

' Add this function to test the code
Function TextureTest() As Void

    ' This directory is temporary and will be available for testing
    l_url = "http://s3.amazonaws.com/NMLiving/texture_test/"
   
   ' I have created 25 simple textures texture1.jpg to texture25.jpg
   l_textureList = CreateObject( "roArray", 25, False )
   
   ' Create the url, the textureobject and push onto the texture list
   for l_i = 1 to 25
      l_turl = l_url + "texture" + l_i.ToStr() + ".jpg"
      l_textureList.Push( NewTextureObject( l_turl ) )
   end for
   
   ' Create an instance of the texturemanager and reset (optional)
   ' However you should know when to reset
   l_textureManager = NewTextureManager()
   l_textureManager.Reset()
   
   print "REQUESTING"
   print "============================================================="
   
   ' For each texture in the list request it from the manager
   for each l_texture in l_textureList
      l_textureManager.RequestTexture( l_texture )
   end for
   
   print ""
   print "RECEIVING"
   print "============================================================"
   
   ' Ask the manager to poll for the textures
   l_textureManager.PollTextures()
   
   ' Verify that we have a valid bitmap for each texture
   for each l_texture in l_textureList
      print type( l_texture.Bitmap )
   end for
   
   
End Function

' Creates a texture cache object which contains the returned bitmap, the textureRequest
' a Url and a resend count
Function NewTextureObject( a_url As String ) As Object
   return { Bitmap: Invalid, TRequest: Invalid, TUrl: a_url, ResendCount: 0 } 
End Function

' Very stripped down version of my own manager.  This version offers only polling
' you would not use polling to populate a grid during realtime scrolling on for preloading
Function NewTextureManager() As Object

   tl = CreateObject( "roAssociativeArray" )
   
   tl.TManager = CreateObject( "roTextureManager" )
   tl.TMPort   = CreateObject( "roMessagePort" )
   tl.TManager.SetMessagePort( tl.TMPort )
   
   tl.RequestList = CreateObject( "roAssociativeArray" )
   
   tl.SendCount = 0
   tl.ReceiveCount = 0
   
   tl.STATE_READY   = 3
   tl.STATE_FAILED  = 4
   
   tl.AddItem    = tl_add_item
   tl.RemoveItem = tl_remove_item
   tl.Reset = tl_reset
   
   tl.RequestTexture = tl_request_texture
   tl.ReceiveTexture = tl_receive_texture
   tl.PollTextures   = tl_poll_textures
   
   return tl
    
End Function

' Adds an item to the list and increments the list count. The key is the textures id
Function tl_add_item( a_ID As Integer, a_value As DYNAMIC ) As Void
   m.RequestList.AddReplace( a_ID.ToStr(), a_value )
   m.ListCount = m.ListCount + 1
End Function

' Removes an item from the list, decrements the count
Function tl_remove_item( a_ID As Integer ) As Object
  
   l_key   = a_ID.ToStr()
   l_value = m.RequestList.LookUp( l_key )
      
   if l_value = Invalid then return Invalid
   
   m.RequestList.Delete( l_key )
   m.ListCount = m.ListCount - 1
      
   return l_value
   
End Function

' Resets the list by emptying the manager and clearing
' out any items remaing, resets all values
Function tl_reset() As Void
    
   m.TManager.CleanUp()
   m.RequestList.Clear()
  
   m.ListCount = 0
   m.SendCount = 0
   m.ReceiveCount = 0
   
End Function

' Each texture object is sent to this function, which creates the texturerequest and sends it
' It also increments the sendcount
Function tl_request_texture( a_texture As Object ) As Integer
   
   ' Create the texture request and assign to the items TRequest member
   a_texture.TRequest = CreateObject( "roTextureRequest", a_texture.TUrl )
   ' Add the item into the async list
   m.AddItem( a_texture.TRequest.GetID(), a_texture )
   ' Asynchronously request the texture 
   m.TManager.RequestTexture( a_texture.TRequest )
   ' Increment the send count
   m.SendCount = m.SendCount + 1
   ' Return the current total sent
   
   print m.SendCount"   "; a_texture.TUrl
   
   return m.SendCount
   
End Function

' This function receives the texture and processes it, if successful it increments the receive count
Function tl_receive_texture( a_tmsg as DYNAMIC ) As Boolean

   ' Get the returned state 
   l_state = a_tmsg.GetState()
  
   ' If return state is Ready, Failed, or Cancelled - either case, remove it from the list
   if l_state = m.STATE_READY or l_state >= m.STATE_FAILED
   
      ' Removed the received texture from the asynclist. But do not increment the received count
      l_texture = m.RemoveItem( a_tmsg.GetID() )
      ' There SHOULD ALWAYS be one in there if used properly
      if l_texture = Invalid then return False
     
      ' Assign the bitmap to the texture object
      l_texture.Bitmap = a_tmsg.GetBitmap()
      ' A state of 3 with a valid bitmap is complete
      if l_state = m.STATE_READY and l_texture.Bitmap <> Invalid 
        
         ' Increment the receive count and get rid of the texture request
         m.ReceiveCount = m.ReceiveCount + 1
         l_texture.TRequest = Invalid
         
         print m.ReceiveCount;"   "; l_texture.TUrl
         
         return True
      
     ' If a failure occurs you can try to resend it, but usually it is a more serious problem which
     ' can put you in an endless loop if you dont put a limit on it.  I handle it differently but for this
     ' example it is resent a limited number of times
      else if l_state = m.STATE_FAILED and l_texture.ResendCount <= 5
         
         ' Optional
         l_texture.TRequest = Invalid
        
         ' Rebuild and resend
         l_texture.ResendCount = l_texture.ResendCount + 1
         l_texture.TRequest = CreateObject( "roTextureRequest", l_texture.TUrl )
         m.AddItem( l_texture.TRequest.GetID(), l_texture )
         m.TManager.RequestTexture( l_texture.TRequest )
      
         ' Set the global error
         l_str = "Resend Texture Request. State : " + l_state.ToStr()
         l_str = l_str + "  Bitmap: " + type( a_tmsg.GetBitmap() ) + "  ResendCount: " + l_texture.ResendCount.ToStr()
         l_str = l_str + " URI: " + l_texture.TUrl
         
         print l_str
         
         return False
  
      ' This can occur with the dylnamic allocation when the textures are not removed from the queue fast enough
      ' or the resend count has expired, cancelled etc...
      else 
      
         l_str = "Unhandled Message. State: " + l_state.ToStr() + "  Bitmap: " + type( a_tmsg.GetBitmap() )
         l_str = l_str + " URI: " + l_texture.TUrl
         
         print l_str
         
         return False
         
      end if
      
   end if
   
   ' Otherwise it is some other code such as downloading if it even exists.  Never seen it
   return True
   
End Function

' This function simply polls for all the textures to return. To populate a grid during realtime scrolling
' a little modification is needed to the grids I have put out here and this manager  I have this available 
' in my own library
Function tl_poll_textures() As Boolean

   ' Just a timeout here you may want to add something like I do to allow the user to abort under
   ' certain conditions.  That was removed for simplicity
   l_timer = CreateObject( "roTimeSpan" )
   l_timeOut = 45
   l_kp_BK   = 0
   
   l_success = False
   
   while( True )
   
      ' Monitor the managers port 
      l_TMsg = m.TMPort.GetMessage()
      
      if l_TMsg <> Invalid
      
         ' Process the received texture
         m.ReceiveTexture( l_TMsg )
        
         ' When receivecount is = to send count then we have them all
         ' you have to be careful here any abnormality or failure in the chain can effect this
         ' I do it differently with more error checking but this is only a demonstration
         l_success = ( m.ReceiveCount = m.SendCount ) 
         if l_success then exit while
         
         ' Reset the timer
         l_timer.Mark()
         
      end if
      
      ' Should always have a timeout as anything can occur
      if ( l_timer.TotalSeconds() >= l_timeout )
      
         print "TextureRequest Timed Out"
         exit while
         
      end if
      
   end while
   
   return l_success
   
   
End Function

Thank you NewManLiving for sharing the code. This code is great, I tried it with my app and the same issue happens.

But I got some insight of what is going on. My images are huge, even though they are grid thumbnails and each of it is around 90kb in size (1050 X 590). It starts failing exactly after 16 successful requests.

I tried the same code with smaller images of 43kb (460 X 360) and it passed! All requests passed successfully.

So I think my assets are going over limit (in terms of dimension - width and height of images) what texture Manager can handle. Any thoughts?

Your probably running out of memory my friend

Open up a telnet session at the box ip and port
Issue the command r2d2_bitmaps. The first time
The command will fail. The second + times will
Allow you to see how much memory your
Images are using.

Port is 8080 for me

r2d2_bitmaps says:

Available memory 114048 used 69885952 max 70000000

Does that mean out of max 70000000 bytes, the app already used 69885952 ?

Yes it does. And if you plan on supporting
The 2 boxes then you have even less, a little more than
Half the memory if the 3 box. 38 or 39 depending
On the firmware. You did indeed run out of memory
Read the documentation on roBitmap for some
Further insight

One other thing you should be aware that a 200 * 200 bitmap is just that in memory, regardless of the type and size of the file. For example a png might be larger
than a jpg but since they are both 200 * 200 they occupy the same amount of memory. The smaller file size is important only for downloading. As far as ROKU memory is concerned there is no difference. You can use roURLTransfer to write your images to disk and open and discard as the user moves along. You can also do this with
the texturemanager by creating what I call a cache cloud. It appears to have some sort of LRU so the next loading is faster. You just load and unload as you go along
However, in my opinion, Program design within the modest limitations of ROKU memory constraints is the primary issue. Would be nice if it had the same memory as
Apple TV or even the new Fire TV. Been dabbling with that as well. Got my eclipse set up for both environments. But Fire TV has its pitfalls as well. Android based
girds are clunky. Bloated Java Code with a ton of packages just to say 'Hello World". Really like the ROKU the best for development. Just does not have it in the memory department

Ok, I think you can help me in this issue:

I have a series of screens with grid populated through texturemanager. When I load the main (home) page:
Available memory 26452096 used 23547904 max 50000000

Once I go from the main page, there is another page with grid generated similarly.
At this point of time; r2d2_bitmaps says:
Available memory 6111360 used 43888640 max 50000000
and is understanable.

But once I navigate back to the main page, i am disposing all the bitmaps to free up the memory.


function dispose() as   
    m.manager.CleanUp()
    m.requestList.Clear()
    
    m.ListCount = 0
    m.sendCount = 0
    m.receiveCount = 0   
end function

but still r2d2_bitmaps says:
Available memory 6111360 used 43888640 max 50000000

Which actually means that, bitmaps remain in the memory. and eventually app goes out of memory and crahses.
How to deal with this?

All bitmap variables that were assigned to any list
Must be set to invalid. All held texture requests
Must be set to invalid

Not home right now but the idea is

For each texture in texturelist
Texture.bitmap = invalid
Texture.TRequest = invalid
End for

All and every held reference must be set
To invalid like any other object before memory
Is released

If you look at your telnet list
You can see the bitmaps that are still
In memory. They are the same size as
Your images with 3 extra bytes. May be 4
Don’t really look at those extra bytes much
When you don’t see them in the
List anymore then they
Are all released. There is one exception
Which occurs when bitmaps are released
And swapbuffers or finish is not called
Then you may notice hanging bitmaps

People on here worked without r2d2_bitmaps
For years. I would have packed it away
If I had to keep guessing or constantly
Measuring.

viewtopic.php?f=34&t=71353

“sonnykr” wrote:
Ok, I think you can help me in this issue: I have a series of screens with grid populated through texturemanager. When I load the main (home) page:
Available memory 26452096 used 23547904 max 50000000

Once I go from the main page, there is another page with grid generated similarly. At this point of time; r2d2_bitmaps says:
Available memory 6111360 used 43888640 max 50000000
and is understanable.

But once I navigate back to the main page, i am disposing all the bitmaps to free up the memory. … but still r2d2_bitmaps says:
Available memory 6111360 used 43888640 max 50000000
…eventually app goes out of memory and crahses. How to deal with this?
I saw you opened new topic but answering here, since there you don’t mention using roGridScreen; here you do and i think it might be important. Are you getting rid of the roGridScreen before returning to main menu or is it lingering still in some variable/global?

I seem to remember roGridScreen is a very special beast with special treatment for video memory and “damaging” some underlying screens (or was it the other way around. don’t think was documented but can be found on the forum). My impression is it is a greedy beast and having >1 grid screen in existence is looking for trouble.