Issue with audio timedMetaData ID3 frame

I am switching from the old method of using a video object and am now using an audio object since timedMetaData support was added in 10.5.

I am able to get good values for TIT2 and TPE1, but our WXXX frame is being modified in a way that I cannot translate into something usable. Due to limitations in our stream hosting provider, we are using the WXXX (user URL) frame to provide a GUID ID of the current song.

Expected result: b1872a6e-3aed-4be9-b523-936cbf06873e

Actual result:

0055524C0062313837326136652D336165642D346265392D623532332D39333663626630363837336500

I can’t really help because I’ve never used ID3 frames, but I do notice it’s a sort of hex ASCII representation of your GUID starting after the 0055524C00 (which would be “URL” surrounded by nulls):

62 - b
31 - 1
38 - 8
37 - 7
etc.

Wow! Good eye! I put the whole thing in a hex to text converter and got “URL b1872a6e-3aed-4be9-b523-936cbf06873e”. Now I just need to figure out how to perform that conversion in Brightscript…

Just a note for anyone else trying to convert hex to ASCII, here is my function:

function convertHexToText(hex as string)
   text = ""
   i = 0
   len = Len(hex)
   while i < len
      segment = Mid(hex, i + 1, 2)
      ascii = Val(segment, 16)
      decoded = Chr(ascii)
      text = text + decoded
      i = i + 2
   end while
   return text
end function

Probably other ways to do it, but this one does the job :blush:

I did find the HexToASCII function buried in the documentation but it gave me odd errors when I tried to use it.

@Arrakis90 could you share an example of your working code with audio object?

i couldn’t get this to work. onTimedMetaData doesn’t get called

m.audio = createObject("roSGNode", "Audio")
m.audio.notificationInterval = 0.1
m.audio.timedMetaDataSelectionKeys = ["*"]
m.audio.observeField("timedMetaData", "onTimedMetaData")

contentNode = CreateObject("roSGNode", "ContentNode")
contentNode.url = content.audioUrl
contentNode.title = content.title

m.audio.content = contentNode
m.audio.control = "play"

function onTimedMetaData()
    print("--TimedMeta Start--")
    print(m.audio.timedMetaData)
    print("--TimedMeta End--")
end function

Hey @duke360 ,

Sure here is a snippet of ours. Note that we had to switch to a video node (even though we don’t display any video) because our analytics provider code didn’t work with an audio node.

sub audioInit()
   print "audio.brs audioInit()"
   m.audio = createObject("roSGNode", "Video") 'We must use a Video component due to Youbora only supporting Video
   m.audio.observeField("state", "audioStatus")
   m.audio.timedMetaDataSelectionKeys = ["TIT2","TPE1","TUID"]
   m.audio.observeField("timedMetaData", "timedMetaDataChanged")
   m.audio.control = "stop"
end sub

sub timedMetaDataChanged()    
   if m.audio.timedMetaData["tit2"] <> invalid then
      appendMessage(m.audio.timedMetaData["tit2"].ToStr() + " - " + m.audio.timedMetaData["tpe1"].ToStr() + " : " + m.audio.timedMetaData["tuid"].ToStr())
      if m.automationId <> m.audio.timedMetaData["tuid"].ToStr()
         appendMessage("Detected new song")
         m.automationId = m.audio.timedMetaData["tuid"].ToStr()
         callSongInfoAutoId()
      end if
   end if
end sub

If I recall from when I made this change, I may have had issues with the wildcard selector “*” and had to explicitly choose which keys I wanted.

Hmm… I notice in the documentation for the old roAudioPlayer, to get all the keys you specify an empty array, not [“*”]. It might be worth trying an empty array.

The docs mention in the details that “If any entry in this array is “*”, then all timed meta data will be selected”. Referenced here: https://developer.roku.com/docs/references/scenegraph/media-playback-nodes/audio.md

@Arrakis90 , I know that. What I’m trying to say is the documentation may be wrong. One component takes “*” and another takes an empty array?! I know this is Roku, but maybe the documentation is wrong in one place or the other.