How to determine the reason for stop?

To discuss development of addons / skins / customization of MediaMonkey.

Moderators: jiri, drakinite, Addon Administrators

Unknown

How to determine the reason for stop?

Post by Unknown »

How to determine if file stopped playback forcefully by user/script or after player finished playing all files from Playing without interruption?

The playbackState is 'stop' in both cases, the playbackend is fired in both cases.
drakinite
Posts: 965
Joined: Tue May 12, 2020 10:06 am
Contact:

Re: How to determine the reason for stop?

Post by drakinite »

To my knowledge it's not possible to do that with only an event handler, but you could override actions.stop to run your own code before (or after) telling the player to stop.

This is the original stop action in actions.js:

Code: Select all

        stop: {
            title: function () {
                return _('Stop');
            },
            icon: 'stop',
            hotkeyAble: true,
            category: actionCategories.playback,
            execute: function () {
                app.player.stopAsync();
            },
            disabled: function () {
                return window.settings.UI.disablePlayerControls.stop /*|| !app.player.isPlaying*/ ; // stop should be active even if playback is paused
            }
        }
in your addon (in actions.js), cache the original function as a local variable, then override actions.stop.execute with your own code, and call the cached function when you're done with your handler.

Code: Select all

var cached_function = window.actions.stop.execute;
window.actions.stop.execute = function () {
    // execute whatever code you wish
    console.log('Player Stop was manually called!');
    // and now, call the original function
    cached_function();
}
You'd then need a way for that overridden execute function to "communicate" with the event handler. One way to do that would be to store the current time (Date.now()) as a global variable (e.g. "lastTimeStopWasPressed"), and then in your playbackstate handler, check to see if the current time is close enough to lastTimeStopWasPressed to assume they happened at the same time. (Not sure how long the stopAsync() function and the corresponding event takes to fire, but half a second should probably more than cover it.)
Image
Student electrical-computer engineer, web programmer, part-time MediaMonkey developer, full-time MediaMonkey enthusiast
I uploaded many addons to MM's addon page, but not all of those were created by me. "By drakinite, Submitted by drakinite" means I made it on my own time. "By Ventis Media, Inc., Submitted by drakinite" means it may have been made by me or another MediaMonkey developer, so instead of crediting/thanking me, please thank the team. You can still ask me for support on any of our addons.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

Thanks for your elaborate answer, it is really appreciated.

If I understand correctly, your solution is only to find when user clicked Stop, but I need to respond on any terminations of playback, even those caused by other scripts. And that thing about communicating with the event handler and hoping that "the current time is close enough" looks just like a dirty hack.

MM4 had OnCompletePlaybackEnd that was "called when track playback is finished because the end of track is reached and no other track is going to be played. i.e. Playback stops, because playlist reached its end." Which is different than OnStop that was "called when playback is stopped (but only stopped by Stop button)."

The current MM5 behavior is that playbackend and playbackState ('stop') are both generated after every track finished playing, which is the same as the old OnPlaybackEnd that was "called when track playback is finished regardless of reason, i.e. either end of track is reached, user presses Stop, Next or Previous button, or there's any other reason for stopping playback."

Which all means that I cannot port my scripts to MM5 until you do something about this.
drakinite
Posts: 965
Joined: Tue May 12, 2020 10:06 am
Contact:

Re: How to determine the reason for stop?

Post by drakinite »

That is a fair reason for differentiating between the two types of stop events. Tracked as: https://www.ventismedia.com/mantis/view.php?id=18951

It's true that my solution is a dirty hack, but it would probably work anyways. But after the fix is added, it'll not be necessary.
Image
Student electrical-computer engineer, web programmer, part-time MediaMonkey developer, full-time MediaMonkey enthusiast
I uploaded many addons to MM's addon page, but not all of those were created by me. "By drakinite, Submitted by drakinite" means I made it on my own time. "By Ventis Media, Inc., Submitted by drakinite" means it may have been made by me or another MediaMonkey developer, so instead of crediting/thanking me, please thank the team. You can still ask me for support on any of our addons.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

Thank you very much for doing that. I am looking forward to test it if it works as I need.

It is very important for me that the firing order of these events is the following:
- playbackState 'completeEnd';
- playbackState 'stop' or playbackEnd (currently, these two are almost the same anyway).

In another words, I need to know the real reason for the payback end in the playbackState 'stop' or playbackEnd events, not after them.

Maybe it would be better if you just added one new property, lets call it endReason or reasonForEnd or something like that, which would be available in the playbackState 'stop' or playbackEnd events, with the following possible values:
1. playback of track is finished because end of track is reached;
2. playback of track is finished because end of track is reached and no other track is going to be played;
3. playback of track is finished because user presses Stop, Next or Previous button, or there's any other reason for stopping playback.

And maybe that third state could be separated to these individual cases:
3. because of Stop (the old OnStop event);
4. because of Next;
5. because of Previous;
6. because of any other reason.

Many of these states could be checked out within the existing events like trackSkipped and by testing some existing properties like isPlaying, but for scripters it would be much simpler and better to have all info in just one place.

One more thing to consider. Is it really necessary that we have getCurrentTrack in the playbackState 'stop' and playbackEnd events as the next file that is in the list? The old SDB.Player.CurrentSong in OnPlaybackEnd, OnTrackEnd and onStop showed the SDB.Player.CurrentSong that is just finished playback, not the next one.

Here is what I get with MM5 after double click on Track1, playing it and pressing stop on Track2 before its end:
- playbackState 'trackChanged' - isPlaying = false, getCurrentTrack = Track1, getNextTrack = Track2;
- playbackState 'play' - isPlaying = true, getCurrentTrack = Track1, getNextTrack = Track2;
- playbackState 'stop' - isPlaying = true, getCurrentTrack = Track2, getNextTrack = Track3
-> MM4 didn't have playbackState 'stop', but it had OnTrackEnd instead, which had CurrentSong = Track1;
- playbackend - isPlaying = true, getCurrentTrack = Track2, getNextTrack = Track3
-> in OnPlaybackEnd event of MM4 that still would be CurrentSong = Track1;
- playbackState 'trackChanged' - isPlaying = true, getCurrentTrack = Track2, getNextTrack = Track3;
- playbackState 'play' - isPlaying = true, getCurrentTrack = Track2, getNextTrack = Track3;
- playbackState 'stop' - isPlaying = false, getCurrentTrack = Track2, getNextTrack = Track3;
- playbackend - isPlaying = false, getCurrentTrack = Track2, getNextTrack = Track3.

As you could see:
1. the current playbackState 'stop' and playbackend have the same values for isPlaying, getCurrentTrack and getNextTrack, so one of these events is redundant;
2. the getCurrentTrack actually returns the next file in playbackState 'stop' and playbackend if there is no interruption in playback and there exists other track in the list that follows;
3. the getCurrentTrack returns the real current file (i.e. the same as it is in the previous playbackState 'play' event) in playbackState 'stop' and playbackend if user presses Stop or the track reached the end and no other track is going to be played.

Well, such behavior is in fact helping me to determine if the playback reached the end, but without your new event I cannot know what is the reason for that end.

Since the playbackState 'stop' and playbackend events are almost the same, I suggest that you make the first one compatible with the old OnTrackEnd event, i.e. the getCurrentTrack in playbackState 'stop' should return the file that just finished play, not the next one. And playbackend could stay as it is now.
MiPi
Posts: 878
Joined: Tue Aug 18, 2009 2:56 pm
Location: Czech Republic
Contact:

Re: How to determine the reason for stop?

Post by MiPi »

Event completeEnd is called at the very end, stop is called when track is stopped, and then, when no next track is going to be played, completeEnd is called (it is the same like in MM4). Opposite order is logically wrong. But you can wait few milliseconds (using requestTimeout) to find out, whether completeEnd arrives too.

Function getCurrentTrack in playbackState event handler always returns current track, it cannot return previously stopped track. You need to take into consideration, that events are asynchronous, so during handling of new playbackState playback of the next track could already start in another thread. You can keep currently playing track by listening to playbackState event - trackChanged state. When stop arrives, track fetched during handling last trackChanged event is the one which just stopped.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

My scripts decide what should be played next in the OnPlaybackEnd, and one parameter for that decision is checking if the end was caused forcibly by Stop button or because there is no more tracks to be played. So, I cannot wait few milliseconds to find that out. Well, to be honest, you are right. I did exactly that with MM4 and because of that I was getting unpleasant sound interruption between tracks. I was hopping that the things with MM5 will be better, but it seems I am out of luck.

The old SDB.Player.CurrentSong in OnPlaybackEnd returns the track that just finished, not the next one that should be played, and I don't see why the getCurrentTrack would behave differently in the analogue playbackState 'stop' event. Function getCurrentTrack in the playbackState event handler do not return the current track always, as you could see in 2. and 3. from my example.

Anyway, I suppose that that part with the current track is not too much important as the first one. I could overcome the current track behavior using the global variable that will contain the track assigned in the playbackState 'play' as the current track. However, the bigger problem that doesn't have any workaround is because I need to know the reason why playback ended in the playbackEnd event, not after it.
MiPi
Posts: 878
Joined: Tue Aug 18, 2009 2:56 pm
Location: Czech Republic
Contact:

Re: How to determine the reason for stop?

Post by MiPi »

SDB.Player.CurrentSong internally calls the same - player.getCurrentTrack, you talk about how you used it in MM4? It worked differently there.
And as I wrote before, playbackState event is asynchronous (has to be), it sends massage to Chromium window, and before Chromium window with your playbackState handler receives this message with this event and runs your listener code, main app skips to the prepared next track, so when you call getCurrentTrack then, you receive this new track (2). In case it does not skip to new track (point 3, manual stop, or none exists), you still receive the last track played, as it is still current (highlighted) track.
For tracking current track I recommend 'trackChanged' state of playbackState event, it was created exactly for this purpose, it is called whenever currentTrack is changed.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

Yes, when I mentioned SDB.Player.CurrentSong I talked about MM4. I think that the 'trackChanged' state of playbackState event is not recommended for tracking the current track because the playback could start without that state, for example if you double-click the currently focused track in Playing panel. I found that 'play' state of playbackState event is more convenient for my use.

The asynchronous way of MM5 execution is great on paper, but it doesn't help me in this case. Is there any way that I could intercept sending message to Chromium window about the next track that should be played, i.e. to send it info about what track I want to play next instead, without causing any sound interruptions as was the case with MM4?
MiPi
Posts: 878
Joined: Tue Aug 18, 2009 2:56 pm
Location: Czech Republic
Contact:

Re: How to determine the reason for stop?

Post by MiPi »

Unknown wrote: Tue Mar 29, 2022 2:22 pm Yes, when I mentioned SDB.Player.CurrentSong I talked about MM4. I think that the 'trackChanged' state of playbackState event is not recommended for tracking the current track because the playback could start without that state, for example if you double-click the currently focused track in Playing panel. I found that 'play' state of playbackState event is more convenient for my use.
When you doubleclick current/highlighted track, it does not call trackChanged, because you did not change current track, you only started playback of current track. There is probably some misunderstanding, “current track” is track highlighted in Playing list, no matter if currently playing or not. If you need to detect start of playback, you really need to catch play state, if you want to track changes of current track (what is returned by player.getCurrentTrack), trackChange is the right state.
Unknown wrote: Tue Mar 29, 2022 2:22 pm The asynchronous way of MM5 execution is great on paper, but it doesn't help me in this case. Is there any way that I could intercept sending message to Chromium window about the next track that should be played, i.e. to send it info about what track I want to play next instead, without causing any sound interruptions as was the case with MM4?
Next track is prepared for playback before ending previous track, so after onTrackEnd it is already very late anyway for such decision. Couldn't you do it in advance? E.g. add next track to playing list when getNextTrack returns already nothing.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

MiPi wrote: Tue Mar 29, 2022 2:51 pm There is probably some misunderstanding, “current track” is track highlighted in Playing list, no matter if currently playing or not.
Yes, I need to detect start of playback and I am sorry for not being specific. When I said the "current track", I meant the "currently playing track".
MiPi wrote: Tue Mar 29, 2022 2:51 pmNext track is prepared for playback before ending previous track, so after onTrackEnd it is already very late anyway for such decision. Couldn't you do it in advance? E.g. add next track to playing list when getNextTrack returns already nothing.
I cannot do it in advance. First of all, my scripts decide which track should be played next not only on the end of complete playback, i.e. when there are no more tracks to be played, but on the end of every played track as well. Secondly, the things are much more complicated in Shuffle mode when the track next in the Playing list is not necessarily the next that will be played.

Maybe it could work if you:
1. allow getNextTrack method to return the next track prepared for playback even in shuffle mode;
2. add new setNextTrack method that will determine the next playing track, without removing any track from your internal playback list used in shuffle mode.
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

By the way, it is great that you added that getNextTrack method in MM5, but its current implementation is pretty useless for scripters:

- if the Shuffle mode is switched off, it is not needed since it could be easily determined which track will be played next;
- if the Shuffle mode is switched on, when it could be really useful to know which track will be played next, that method returns undefined.
Peke
Posts: 17558
Joined: Tue Jun 10, 2003 7:21 pm
Location: Earth
Contact:

Re: How to determine the reason for stop?

Post by Peke »

Hi,
Can you please retest with 2612+ where playbackState event on player object receive 'completeEnd' https://www.ventismedia.com/mantis/view ... 951#c67377
Best regards,
Peke
MediaMonkey Team lead QA/Tech Support guru
Admin of Free MediaMonkey addon Site HappyMonkeying
Image
Image
Image
How to attach PICTURE/SCREENSHOTS to forum posts
Unknown

Re: How to determine the reason for stop?

Post by Unknown »

I cannot test it right now since 2612 is not available yet. However, I found my own way to get the same effect even without that new state in playbackState event: I just check out in the 'end' state if (currentPlaylistPos === app.player.playlistPos && !app.player.isPlaying) and then (app.player.trackLengthMS - app.player.trackPositionMS > 500) and if that is true I assume it was the same as with the old Stop event when user stopped playback, otherwise I assume that playback finished naturally without interruption.

As I said, your new 'completeEnd' state is not much useful for me since it is appearing after 'stop' state. And I need to know the reason for stop as early as it is possible. I don't want to use some hacks with setTimeout and to hope if that 'completeEnd' state will happen inside that timeout or not. What if I choose 10 ms for timeout and that state happens after 15 ms? I already had such hacks before with MM4, I just hoped things are going better with MM5.

Please consider my suggestions if you want things better:
1. add new property which will indicate the reason for end of playback in the 'end' state of playbackState event;
2. allow getNextTrack method to return the next track prepared for playback in shuffle mode;
3. add new setNextTrack method that will determine the next playing track.

If you implement the third suggestion, I think I will not need the first two.
Peke
Posts: 17558
Joined: Tue Jun 10, 2003 7:21 pm
Location: Earth
Contact:

Re: How to determine the reason for stop?

Post by Peke »

Hi,
Hmmmm, interesting. You really made me think about all this.

as for 3. You should be able to set current track on end at least that is how I have done it in MM4, but I like your proposal where you can setNextTrack as Object which would allow queue non Now playing track by your choice to be played next like Queue script in MM4 and will also not interrupt Now Playing. Something like my QuickPlay Plugin and few others I used for radio where there is timings for injecting ads, jingles, announcements, ... withing now playing without interrupting normal flow of playlist.

As for 2. Internally with team I commented "...regarding Shuffle mode which have space to improve eg. getNextTrack should be already filled when event triggers eg. even in shuffle mode it will know next track, but in case of playbackState -> CompleteEnd getNextTrack should be empty or undeffined...." which I think should be enough to know determine many more cases.

as for 1. I am not so sure about it and it is possible that will add additional confusion to implementation, but again maybe I am wrong.
Best regards,
Peke
MediaMonkey Team lead QA/Tech Support guru
Admin of Free MediaMonkey addon Site HappyMonkeying
Image
Image
Image
How to attach PICTURE/SCREENSHOTS to forum posts
Post Reply