How to stop an addon when player stops while playing a nonstandard satip rtsp stream?
#1
Hi 
it's hard to compress a long question into the small subject text field.. :-)

Here are more details:

Here in germany you can get small Sat>IP servers, which stream SAT TV as rtsp stream. In fact they are just promised to do so, but the reality is different.

I tried to receive such a rtsp:// stream with Kodi, but neither Kodi nor ffmpeg nor curl nor... is able to receive it, only VLC is able to show such a stream, and after much to much WireSharking, googleing and specification reading I now ended up with a functional python script, which does the necessary protocol handshake and starts Kodi to receive the stream by the jsonRPC call Player.Open()

But there are 2 problems left:
  • Because of Sat>IP specification limitations I've to initiate the handshake from the same machine (= ip address) on which also the player is running
  • I've to send a regular keep alive message, so I can not simply end the starting script after starting up the Kodi player
And as I use Kodi just as "headless" Player, I need to control also my script via jsonRPC.

So I'm now searching for the right way to do
  1. starting my script via jsonRPC. This works already via Addons.ExecuteAddon()
  2. let my script run in the background to send the regular keep alive message to the Sat>IP server - no problem on that
  3. But how to make that script to stop again with another jsonRPC command Huh - most prefered somehow linked to the player itself, because if the user stops the player anyhow, I would need to stop the keepalive signal and to send additonal termination commands to the Sat>IP server to release the locked channel resource again.. Does Kodi have a kind of internal event messaging on which my script could get a notification that the Player has stopped?
To be honest, I've no clue how to manage this - I've just started with Kodi and have no idea how such things could be done or e.g. how the other video plugins do something like this....  Confused

Maybe you have a good hint how to make this?


thanks in advance

Steffen
Reply
#2
Sounds like this is the perfect use case for an inputstream addon
Reply
#3
(2020-12-11, 23:23)enen92 Wrote: Sounds like this is the perfect use case for an inputstream addon

Sounds like this is the perfect answer to my question  Wink

Do you or anybody else has a good hint where I could find an example of how to design such an inputstream addon? There must be certainly something in the Kodi source repository or on the wiki pages, but I did not found it so far  Rolleyes
Reply
#4
(2020-12-12, 09:51)stko Wrote:
(2020-12-11, 23:23)enen92 Wrote: Sounds like this is the perfect use case for an inputstream addon

Sounds like this is the perfect answer to my question  Wink

Do you or anybody else has a good hint where I could find an example of how to design such an inputstream addon? There must be certainly something in the Kodi source repository or on the wiki pages, but I did not found it so far  Rolleyes

I've now looked through the few samples of inputstreams provided on the xbmc github page, and it appears to me as if an inputstream addon really does supply the input stream . In my case instead Kodi as client is able to play the input stream already (as RTP://), I only need to make a wrapper around to control the satip server to provide the stream to the kodi client.

So I'm not sure if an inputstream addon would be the right approach ?!?
Reply
#5
I am not the best person to answer this but it seems that in Kodi ffmpeginputstream is used to handle rtp streams.

As such, I would probably look into inputstream.ffmpegdirect (https://github.com/xbmc/inputstream.ffmpegdirect) as a starting point, as it uses ffmpeg as well to provide support for timeshift. You can probably fork the project and implement your custom logic in open and close.
Reply
#6
For documentation, doxygen (and code from other inputstream addon examples) are your best friends:
https://codedocs.xyz/xbmc/xbmc/group__cp...tream.html
Reply
#7
(2020-12-12, 11:56)enen92 Wrote: I am not the best person to answer this but it seems that in Kodi ffmpeginputstream is used to handle rtp streams.

As such, I would probably look into inputstream.ffmpegdirect (https://github.com/xbmc/inputstream.ffmpegdirect) as a starting point, as it uses ffmpeg as well to provide support for timeshift. You can probably fork the project and implement your custom logic in open and close.

I'm pretty unsure if I would be able to understand the whole ffmeg software logic to add the right tweaks into it  Sad Over the day I took the script.hello.world example and made something out if, which can be started with an jsonRPC  Addons.ExecuteAddon() call. It does the server initialisation, starts the player and send keepalives until a player.stop event is received, so it basically does what it should do. 

But I'm with you, it would be nice if this could be made as an handler for a pseudo protocol 'satip://' (that's the way how VLC does it), because then all other modules could read from such a satip server easily. But as said, I don't want to (because I simply can't) re-invend the whole ffmeg software for that :-)

Might there be any other way to do it?
Reply
#8
You can define a service extension point in your python add-on and create a xbmc.Monitor class. Inside that monitor class, instantiate a xbmc.Player object and reimplement the onPlaybackStopped or onPlaybackEnded callbacks. There you can filter the item by your plugin identifier (self.getgetPlayingFile()), then implement your custom logic.
In the service entry point instantiate the service and loop (monitor.waitForAbort(secs)) until monitor.abortRequested() is flagged.
Reply
#9
(2020-12-13, 00:19)enen92 Wrote: You can define a service extension point in your python add-on and create a xbmc.Monitor class. Inside that monitor class, instantiate a xbmc.Player object and reimplement the onPlaybackStopped or onPlaybackEnded callbacks. There you can filter the item by your plugin identifier (self.getgetPlayingFile()), then implement your custom logic.
In the service entry point instantiate the service and loop (monitor.waitForAbort(secs)) until monitor.abortRequested() is flagged.
Hello @enen92 
I understand so far, but can I catch and modify the player start request by that? 
  1. Let's say I start a play request with jsonRPC Player.Open for "satip://my_sat_ip_server:554/my_params"
  2. Then my service need to catch the "satip://" request
  3. The Sat>IP server initialisation need to be started
  4. When the server is sending via UDP, then the Kodi player needs to be started with a "rtp://0.0.0.0:my_upd_port"

So  as you can see, I need to catch the original satip:// play request, do something in between and then start the player with another URL

But the function self.getPlayingFile() reports only Urls which are already playing - and this playing would most probably instandly fail as the originat satip:// is not "playable" as such  Huh


So I would need to find some kind of "Pre-Playing" hook callback, which would allow me to delay and modify the url to be played..... 

Good question, isn't it  ? - sorry for that..  Wink
Reply
#10
Afaik, mapping a satip:// virtual path to an add-on is something you can't currently do with python add-ons. This is one of the features of inputstream add-ons. Maybe you can find some oss library you can use to process the RTP stream and feed packets into the video player, it would be much better than any python workarounds.

The maximum you can do with python is to create an add-on with a plugin extension point and a service extension point. Your plugin extension is responsible for resolving a given path to a playable item. For instance you create a "path"/routing entry inside your plugin that receives the playable path as an urlencoded argument:

plugin://plugin.video.satip/play?stream=satip%20....

This path will do your required preprocessing and resolve the stream (setResolvedUrl) to the actual playable RTP:// url.

Your service extension point has a monitor and a player instance. It is responsible for monitoring player events. When onPlayBackStarted event is triggered you look for the path and check if it is from your plugin://plugin.vidro.satip so that your background thread can start to keep the stream alive. onPlaybackStopped would do the opposite.
Reply
#11
(2020-12-13, 12:29)enen92 Wrote: Afaik, mapping a satip:// virtual path to an add-on is something you can't currently do with python add-ons. This is one of the features of inputstream add-ons. Maybe you can find some oss library you can use to process the RTP stream and feed packets into the video player, it would be much better than any python workarounds.

The maximum you can do with python is to create an add-on with a plugin extension point and a service extension point. Your plugin extension is responsible for resolving a given path to a playable item. For instance you create a "path"/routing entry inside your plugin that receives the playable path as an urlencoded argument:

plugin://plugin.video.satip/play?stream=satip%20....

This path will do your required preprocessing and resolve the stream (setResolvedUrl) to the actual playable RTP:// url.

Your service extension point has a monitor and a player instance. It is responsible for monitoring player events. When onPlayBackStarted event is triggered you look for the path and check if it is from your plugin://plugin.vidro.satip so that your background thread can start to keep the stream alive. onPlaybackStopped would do the opposite.
So is my understanding correct that I could give "plugin://plugin.video.satip/play?stream=satip%20...." via jsonRPC as URL to Player.Open()?

Because that would do the job, you are right.. I'll try that

Thanks for your help ! I'll let you know when it's working  Smile

But a hopefully last question: Is there any mechanism in Kodi in place which could help me to control that the plugin is only started once and helps to avoid that the plugin can run multiple times? (like some mutex / locks etc.?)
Reply
#12
The plugin can be called multiple times, it's supposed to resolve the URL and die. If you want to keep state/locks the place for that is in the service extension since it will run in the background. But then you need some sort of communication between your add-on threads (plugin and service). Look for something like addon signals (https://kodi.wiki/view/Add-on:Addon_Signals) for that.
A simpler approach would be to store some filesystem based "lock", i.e., create a dummy file in your add-on userdata folder when your plugin is called and check for that. You might run into some races though.

Honestly the correct way to do this is via inputstream.
Reply
#13
(2020-12-13, 16:08)enen92 Wrote: ...
Honestly the correct way to do this is via inputstream.
You are right on that - but neither the ffmpeg team, curl, wget and some more tools I've tested implemented this satip protocol. And to set up a functional ffmeg build environment, understand the ffmpeg sources at all, find the todays rtsp routines in there, extend them to do also satip and finally test and deploy that all for all Kodi platforms is a little too much for a little programmer like me and for a rainy sunday afternoon  Wink

But maybe we could get a maintainer of the ffmeg part on board on that? If he could at least tell were I need to search in the universe of the ffmeg sources, that could maybe a start...
Reply
#14
If satip is not a standards based protocol it won't get implemented in ffmpeg I'm afraid. Let me ask some questions.

1) Does it work simply if you change the rtsp part of the URL to rtp?
2) Can you give real example URL? (Just change the actual IP if you need to obfuscate it).
3) If it is a custom protocol the only way to get this to work seemlessly is via an inputstream add-on. If you can detail exactly what needs to happen I can advise you on what's the right approach. Well, my best guess anyway Wink
Maintainer of Enigma2 PVR addon: repo, docschangelog
How to create a full debug: here
Reply
#15
(2020-12-13, 17:44)phunkyfish Wrote: If satip is not a standards based protocol it won't get implemented in ffmpeg I'm afraid. Let me ask some questions.

1) Does it work simply if you change the rtsp part of the URL to rtp?
2) Can you give real example URL? (Just change the actual IP if you need to obfuscate it).
3) If it is a custom protocol the only way to get this to work seemlessly is via an inputstream add-on. If you can detail exactly what needs to happen I can advise you on what's the right approach. Well, my best guess anyway Wink
Hi 
here are some answers:

1) the good news is: It is a standard protocol (depends on what makes a standard  Wink )  - but I'm afraid there are not so much users of it...? The spec is here: https://www.satip.info/resources/specification/
2) There is no real example URL, because there are all coming from local devices (the SAT>IP servers), so there is no public URL awailable afaik
3) the protocol of what Kodi is finally receiving is RTP while listening to a UDP port ("rtp://0.0.0.0:60478" works). The main problem is that the serving device needs a periodic TCP message to keep the connection alive and to continue to sent the data stream. The data stream itself is a transport stream with satelite data wrapped in RTP packets
Reply

Logout Mark Read Team Forum Stats Members Help
How to stop an addon when player stops while playing a nonstandard satip rtsp stream?0