Trakt.tv LiveTV scrobble Development help request. (1 Viewer)

mm1352000

Retired Team Member
  • Premium Supporter
  • September 1, 2008
    21,577
    8,224
    Home Country
    New Zealand New Zealand
    Probably a misunderstanding: I don't want to know "when" a new program starts (I have the full guide available), I only want to know the "time" of my current playback position.
    Okay, well I just repeat the same thing in another way. :)
    The SCR, PTS, DTS and PCR are completely independent of program timing. In a stream provided by TV Server they only give you the time relative to when the person started watching TV with the current tuner. There is no connection to program/"airing" time. Further, there is no guarantee that the TsWriter design won't change in future. In fact, I have changed it in my TVE 3.5 branch so that the time is simply relative to when the person starts watching TV. After that, the time increases continuously regardless of channel and tuner changes.
     

    morpheus_xx

    Retired Team Member
  • Team MediaPortal
  • March 24, 2007
    12,073
    7,459
    Home Country
    Germany Germany
    In fact, I have changed it in my TVE 3.5 branch so that the time is simply relative to when the person starts watching TV. After that, the time increases continuously regardless of channel and tuner changes.
    Ah, this would be the useful information :)

    This is the logic I implemented in my "TimeShiftContext" on client side: it records the "tune in time" and how long the program was running. I just would like a more reliable way, because this implementation expects that the timeshift buffer is infinite, but it is not. So if you watch live TV for hours, you will have obsolete information after tswriter recycles tsbuffer files.
     

    Owlsroost

    Retired Team Member
  • Premium Supporter
  • October 28, 2008
    5,540
    5,038
    Cambridge
    Home Country
    United Kingdom United Kingdom
    To add to what mm has said:

    1. All streams (files) that TV Server creates start with all timestamps at zero.
    2. Timeshift streams are part real, part virtual files - the real part (the most recent part) actually exists as files, the virtual part is the older stream data that is no longer available. The timestamps are relative to the start of the virtual file i.e. to zero, and TsReader restricts the seek range to the the 'real' part only (the duration measuring code in TsReader and StreamingServer keeps both a 'real' duration and a 'real+virtual' duration).

    So the only thing TsReader knows is a position (timestamp) in the stream relative to the start of the stream, and the stream duration i.e. end timestamp - start timestamp. It has no concept of real time or date for the stream.
     

    Owlsroost

    Retired Team Member
  • Premium Supporter
  • October 28, 2008
    5,540
    5,038
    Cambridge
    Home Country
    United Kingdom United Kingdom
    expects that the timeshift buffer is infinite

    In terms of timestamps (ignoring the MPEG timestamp rollover), the timeshift stream is infinite - it's only the available data that is finite.

    how long the program was running. I just would like a more reliable way,

    TsReader knows where it is in the stream, so it could provide a 'current timestamp relative to start of timeshift' value to the player.
     

    Alberto83

    Portal Pro
    August 7, 2012
    336
    108
    Home Country
    Italy Italy
    I haven't the code here but i'll post the relevant part when i come back home.

    It basically consists in setting a thread.timer to fire up every "tvhandler.nextprogram.starttime" and then resets it with the "tvhandler.nextprogram.starttime" again if the callback function is fired (and the previous tvhandler.nextprogram becomes the tvhandler.currentprogram) or when there's a new tuning event (and thus a new nexprogram on a new channel).
    The callback function of the timer just creates a tscontext with the new program and adds it to the timeshiftmediaitem.TimeshiftContexes manually, without removing the old one (since we're in the same channel). I basically never remove tscontexts but keep adding them and that's why the recycler is needed to remove old entries somehow (or tombestone them). The tscontext.tuneintime is set to datetime.now every time i have to create a new tscontext (so every time a new channel is tuned, or the callback function runs). This way i have a timeshift context is effectively a timeline of the timeshift.

    It's perfectly safe since if, for a moment, we forget that the TS file is "circular", everything before "NOW" in the timeline cannot be changed. It's there and there stays for the whole lifetime of the stream. When the stream is over, we don't need it anymore.
    Also the timer for the next program is safe, because the only thing that could alter that timer is a new tuning event on that stream where we need to reset the timer with a different nextprogram.starttime. Zapping isn't a big deal, we're not tuning while zapping.
    Since i'm using the tvhandler.currentprogram and tvhandler.nexprogram this isn't affected by pausing the tsreader.
    I don't know if i explained that well, i'll post the code.

    When i thought of doing it "server side" i was thinking more of creating the entire TSContext logic on the server (per stream, like now on my solution) and return the relevant portion to the client every time we use the timeshift feature. Since the server, and only the server, can write the stream, it seemed logical to me that it should be the only one that should create and handle this sort of "timeline" and recycle old programs.
    Moreover, this would open up to sharing streams (and it's timeline) to all clients that connect to that stream. (EDIT: i'm more thinking about placeshifting than really sharing the stream)
    Instead of embed those properties in the TS file which seems too complex, what about storing the whole timeline data on the server memory and ask for it from the client based on the tsreader position? This would make them indipendent from the tswriter, right?
     
    Last edited:

    Alberto83

    Portal Pro
    August 7, 2012
    336
    108
    Home Country
    Italy Italy
    These are the changes to the SlimTVHandler.cs
    C#:
    /*snip*/
    private struct TVSlotContext
            {
                public bool IsPiP;
                public bool CardChanging;
                public string AccessorPath;
                public IChannel Channel;
                //one timer for each slot.
                //@ASK!!! What about doing this server side? one timeline for each stream? Would definitely solve placeshifting issues.
                public Timer nextProgramWatcher;
            }
    /*SNIP*/
    private bool AddOrUpdateTimeshiftContext(LiveTvMediaItem timeshiftMediaItem, IChannel channel)
            {
                //Do this ASAP so the timer is as close as possible to the real program time change.
                System.DateTime currentTime = System.DateTime.Now;
                //Need to check if a timer is already set before dispose it
                if (_slotContexes[(int)timeshiftMediaItem.AdditionalProperties[LiveTvMediaItem.SLOT_INDEX]].nextProgramWatcher!=null)
                    _slotContexes[(int)timeshiftMediaItem.AdditionalProperties[LiveTvMediaItem.SLOT_INDEX]].nextProgramWatcher.Dispose();
                if (timeshiftMediaItem.TimeshiftContexes.LastOrDefault() != null) 
                {
                    //this is not the first context, so so get the one before and set its duration.
                    timeshiftMediaItem.TimeshiftContexes.Last().TimeshiftDuration = currentTime.Subtract(timeshiftMediaItem.TimeshiftContexes.Last().TuneInTime);
                }
                TimeshiftContext tsContext;
                if (CurrentProgram== null) // there's no program information, just go as normal, and don't set a timer to update.
                {
                    tsContext = new TimeshiftContext
                    {
                        Channel = channel,
                        TuneInTime = currentTime,
                    };
                }
                else //populate tscontext with program info and set the timer
                {
                     tsContext = new TimeshiftContext
                    {
                        Channel = channel,
                        TuneInTime = currentTime,
                        Program = CurrentProgram
                    };
                    //Add a timer to trigger an update when next program begins.
                    //Start a new timer to call GetNewProgram when the program is due, plus 15 seconds.
                    _slotContexes[(int)timeshiftMediaItem.AdditionalProperties[LiveTvMediaItem.SLOT_INDEX]].nextProgramWatcher = new Timer(GetNewProgram, timeshiftMediaItem,
                        (tsContext.Program.EndTime - currentTime + System.TimeSpan.FromSeconds(NEXT_PROGRAM_WATCHER_DELAY)), Timeout.InfiniteTimeSpan);
                }
                timeshiftMediaItem.TimeshiftContexes.Add(tsContext);
                timeshiftMediaItem.AdditionalProperties[LiveTvMediaItem.CHANNEL] = channel;
                return true;
            }
            private void GetNewProgram(object o)
            {
                //This will only get called when the current channel does not change.          
                System.DateTime currentTime = (System.DateTime.Now - System.TimeSpan.FromSeconds(NEXT_PROGRAM_WATCHER_DELAY));  //remember the NEXT_PROGRAM_WATCHER_DELAY
                LiveTvMediaItem mi = (LiveTvMediaItem)o;
                //Set offset for the last tscontext
                mi.TimeshiftContexes.LastOrDefault().TimeshiftDuration = (currentTime - mi.TimeshiftContexes.LastOrDefault().TuneInTime);
                //Create the new TSContext
                //first check if the program is null
                if (CurrentProgram == null) //since this function should only triggers when the program change in the current stream, we probably already have epg set, but nobody knows. Bad EPG data?
                {
                    TimeshiftContext tsContext = new TimeshiftContext
                    {
                        Channel = (IChannel)mi.AdditionalProperties[LiveTvMediaItem.CHANNEL],
                        TuneInTime = currentTime,
                    };
                }
                else
                {
                    TimeshiftContext tsContext = new TimeshiftContext
                    {
                        Channel = (IChannel)mi.AdditionalProperties[LiveTvMediaItem.CHANNEL],
                        TuneInTime = currentTime,
                        Program = CurrentProgram  //@NOTE!!!! ok, what if the user changes channel just "a line before??"
                    };
                    //Add the new program to contexes
                    mi.TimeshiftContexes.Add(tsContext);
                    //This is safe
                    mi.AdditionalProperties[LiveTvMediaItem.CURRENT_PROGRAM] = CurrentProgram;
                    mi.AdditionalProperties[LiveTvMediaItem.NEXT_PROGRAM] = (NextProgram != null) ? NextProgram : null;
                    //update timer to the next program change.
                    _slotContexes[(int)mi.AdditionalProperties[LiveTvMediaItem.SLOT_INDEX]].nextProgramWatcher.Change(
                        (tsContext.Program.EndTime - currentTime + System.TimeSpan.FromSeconds(NEXT_PROGRAM_WATCHER_DELAY)), Timeout.InfiniteTimeSpan);
                }
            }
    /*snip*/

    I could optimize the code by calling again AddOrUpdateTimeshiftContext in the callback function but i wanted to keep it separate for easier debugging (not a pro coder, you can tell from my comments to always know what and why i did something. Need more practice, sorry ) my own code.
    With this changes i could get a timeline with just a few milliseconds delay from the real epg data.
     

    Alberto83

    Portal Pro
    August 7, 2012
    336
    108
    Home Country
    Italy Italy
    Hello, definitely I am, it's a strong requirement for trakt tv to work for live TV.
    I had a tough week at work but I'm still here.

    I'm trying to find a solution to implement the timeline feature on the slimtvservice instead on the slimtvhandler class. This should be enough to keep it independent from the tswriter but still server handled. While the current "implementation" actually works, it's clumsy because handling any streams information on the client side is logically wrong since the client only reads the stream.
    The main problem other than retrieving and building a timeline for any stream will be to notify then the client of any change on the portion of the program currently playing in the timeline. I'm a newbie coder so everything requires more time for me :)
     

    Users who are viewing this thread

    Top Bottom