Unreliable playback using xbmc.Player().play()
#1
Hi,

I'm developing an addon for playing internet radio streams. Until now I've been using setResolvedURL() on a xbmcgui.ListItem object to start playback, which works fine. However, I want to take advantage of the callback methods provided by the xbmc.Player class, and get around the behaviour where Kodi assumes that all items in a list are to be placed in a playlist.

The stream I'm testing with is http://stream.scahw.com.au/live/buddha_1...ylist.m3u8

I've tried various options to get this work, and I can't find one that is reliable using xbmc.Player().play()

This works fine:
Code:
li = make_list_item()
li.setPath(stream_url)
xbmcplugin.setResolvedUrl(handle, True, li)

This works sometimes, but two out of three times it fails with a 'Player: skipping unplayable item' entry in the log:
Code:
li = make_list_item()
xbmc.Player().play(item=stream_url, listitem=li)
Omitting the listitem argument behaves the same, just without any artwork or info.

This will cause the Kodi GUI to hang, with an eventual 'Exception caught on main loop' error:
Code:
li = make_list_item()
li.setPath(stream_url)
xbmc.Player().play(listitem=li)

Am I doing something wrong? I would expect the first two examples to work the same, but that's not what I'm seeing.

I'm using Kodi 16.1 on Windows 7.

Cheers,
Jon
Reply
#2
if you're creating a plugin, you'll have to use the first method (afaik).
plugins need to provide kodi with a playable url, and kodi will handle the playback.

the xbmc.Player() class can be used if you're creating a script.
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#3
A workaround is to use setresolvedurl with a blank listitem and false as argument and after that call the xbmc player
Reply
#4
don't workaround. use the api at hand. your plugin is a VFS entry. a VFS entry does NOT start a player, it lists directories (the normal thing), or 'opens files', here in the form of resolving the actual url for playback. anything else is NOT something you are supposed to do in a plugin. as ronie says, that's for scripts. sadly there's no containers for functionality in the python code so you have access to the whole python API from a plugin. to be specific, what happens is that the thread executing the script holds a lock, and the main thread is spinning on the lock. you try to kick off a player from your python script, while holding the lock. nobody's there to listen cause the main thread that is supposed to kick off the player is spinning on the lock you hold. bam, deadlock.
Reply
#5
(2016-10-25, 13:29)ironic_monkey Wrote: don't workaround. use the api at hand. your plugin is a VFS entry. a VFS entry does NOT start a player, it lists directories (the normal thing), or 'opens files', here in the form of resolving the actual url for playback. anything else is NOT something you are supposed to do in a plugin. as ronie says, that's for scripts. sadly there's no containers for functionality in the python code so you have access to the whole python API from a plugin. to be specific, what happens is that the thread executing the script holds a lock, and the main thread is spinning on the lock. you try to kick off a player from your python script, while holding the lock. nobody's there to listen cause the main thread that is supposed to kick off the player is spinning on the lock you hold. bam, deadlock.

Actually, this is not quite true. You can do anything inside you plugin, provided you do your plugin calls routing correctly, as described here: http://forum.kodi.tv/showthread.php?tid=...pid2227469

The 3rd variant from my list allows to execute any Python code inside a plugin without side effects, including caling xbmc.Player(). But it is less functional than using setResolvedUrl, because with setResolvedUrl:
- Bookmarks and watched marks are working correctly.
- You have a correct context menu for your playable items.
- If you launch playback, the player OSD will automatically show correct info and images for your list item being played.

So IMO xbmc.Player() should be used in plugins only in special cases. I cannot remember any such cases right now but I admit that they may exist out there.Smile
Reply
#6
fine, you can twiddle the system to work but my point still stands: none of what is stated there is guaranteed anywhere, it's just how the code happens to be organized. the last thing you want to do is to make this defacto, and end up breaking tons of add-ons when code is reorganized.
Reply
#7
(2016-10-25, 13:29)ironic_monkey Wrote: you try to kick off a player from your python script, while holding the lock. nobody's there to listen cause the main thread that is supposed to kick off the player is spinning on the lock you hold. bam, deadlock.

Is this the case for both the ways I've tried to use xbmc.Player, or just the last one which results in a crash?

(2016-10-25, 13:55)Roman_V_M Wrote: You can do anything inside you plugin, provided you do your plugin calls routing correctly, as described here: http://forum.kodi.tv/showthread.php?tid=...pid2227469

The 3rd variant from my list allows to execute any Python code inside a plugin without side effects, including caling xbmc.Player().
Roman_V_M Wrote: For plugin rules are the following:
- If a ListItem opens a lower lever list, it must have isFolder=True.
- If a ListItem calls a playback function that ends with setResolvedUrl, it must have setProperty('isPlayable', 'true') and IsFolder=False.
- If a ListItem does any other task except for mentioned above, is must have isFolder=False.

I already have isFolder=False on the list item from which the plugin is called. I assume this is what you mean, rather than the list item that's created immediately before starting playback. In which case, my second attempt should work:
Code:
li = make_list_item()  # You don't mean set isFolder=False here...
xbmc.Player().play(item=stream_url, listitem=li)

What's confusing me is that this works only sometimes. I would expect the behaviour to at least be the same each time. I found one other mention of the same problem in the forum, but no response explaining why it might be happening.
http://forum.kodi.tv/showthread.php?tid=...pid1906969

I think I'll try to test this in isolation, to make sure it's not something else in my code that's causing problems.

Anyhow... Since this doesn't seem to be recommended practice, is there a way I can tell Kodi to only play one list item using setResolvedUrl(), instead of making a playlist out of the whole list. This seems to be the main advantage of xbmx.Player().play() in my scenario, since I can emulate the callback functions by periodically checking if my URL is being played or not.
Reply
#8
(2016-10-26, 10:47)jonathan.holvey Wrote:
(2016-10-25, 13:55)Roman_V_M Wrote: You can do anything inside you plugin, provided you do your plugin calls routing correctly, as described here: http://forum.kodi.tv/showthread.php?tid=...pid2227469

The 3rd variant from my list allows to execute any Python code inside a plugin without side effects, including caling xbmc.Player().
Roman_V_M Wrote: For plugin rules are the following:
- If a ListItem opens a lower lever list, it must have isFolder=True.
- If a ListItem calls a playback function that ends with setResolvedUrl, it must have setProperty('isPlayable', 'true') and IsFolder=False.
- If a ListItem does any other task except for mentioned above, is must have isFolder=False.

I already have isFolder=False on the list item from which the plugin is called. I assume this is what you mean, rather than the list item that's created immediately before starting playback. In which case, my second attempt should work:

Please read my post carefully. For plugin routes that do not create sub-listings or call setResolvedUrl (the 3rd variant), isFolder=False is the only thing that you need to do. You must not touch 'isPlayable' property in this case.
Reply
#9
(2016-10-26, 12:08)Roman_V_M Wrote: Please read my post carefully. For plugin routes that do not create sub-listings or call setResolvedUrl (the 3rd variant), isFolder=False is the only thing that you need to do. You must not touch 'isPlayable' property in this case.

Yep, you're right. I found this just now while testing a stripped down sandbox addon. Thanks for your help. Smile
Reply
#10
it's just the one case if the other works. what i state is what is guaranteed, but it's a simplification. there are, as roman points out, certain ways you can "game the system". problem is if that gaming becomes a de-factor standard you are locked into that behavior should you want to refactor. something that was never intended.
Reply
#11
(2016-10-27, 11:59)ironic_monkey Wrote: it's just the one case if the other works. what i state is what is guaranteed, but it's a simplification. there are, as roman points out, certain ways you can "game the system". problem is if that gaming becomes a de-factor standard you are locked into that behavior should you want to refactor. something that was never intended.

While I appreciate that we are taking advantage of an unintentional quirk of the API, you can't deny that the three scenarios presented by it are inherently useful. Even if backwards compatibility is removed at some point, I feel that it would be sensible for any refactoring to allow for these scenarios in an official way, rather than removing the functionality simply because it wasn't originally planned.

Until that time I'm willing to take the risk by using it, if there is no alternative way to achieve what I'm trying to do. Wink
Reply
#12
sure, i aboslutely understand both perspectives, i also own a copy of each of those hats Wink

i absolutely agree that the refactoring makes sense, but we do not want to decide the how up front, just the what, if you get my drift.
Reply
#13
(2016-10-25, 13:55)Roman_V_M Wrote: So IMO xbmc.Player() should be used in plugins only in special cases. I cannot remember any such cases right now but I admit that they may exist out there.Smile

I have one... I'm listing TV channels from the json api. Playback with setresolvedurl isn't possible because there's no way (I know of) to get the playback url/file for the TV channel. Instead I run the json command Player.Open with the channelid.

Thanks for the hint with not setting isPlayable property, that indeed does the trick, no more errors now.
Reply

Logout Mark Read Team Forum Stats Members Help
Unreliable playback using xbmc.Player().play()0