Problem bei 'OnPlayerStop' und 'IPlaylistItem'

Ausgangssituation:
Ich habe 14 Titel in der Playlist.
Starte den ersten , befinde mich im Assist-Mode.
Wenn dieser Titel zu Ende ist, wird ja ‘OnPlayerStop’ ausgelöst.
Aber warum ist die Anzahl der Einträge in der Playlist dann immer noch 14, obwohl der Titel gespielt wurde und aus der Playlist entfernt wurde.
Ich hätte vermutet, das hier dann eben als ‘CurrentPlaylist.GetCount’ nur noch 13 vorhanden sind.

Ich vermute irgendwo ein Timing-Problem.
Wenn dem so ist, wie lässt sich das umgehen ?

Folgendes Hintergrund-Script als Beispiel:

procedure OnPlayerStop(PlaylistIndex: integer; PlayerIndex: integer; Duration: TTimeValue; Item: IPlaylistItem);
var 
    playlist_count: Integer;
	idx:Integer;
	pi: IPlaylistItem;
	titel, artist: string;  
	  
begin
playlist_count := CurrentPlaylist.GetCount;
SystemLog('playlist_count ' + IntToStr(playlist_count));
while idx < playlist_count do
  begin
    pi := CurrentPlaylist.GetItem(idx);
		titel := pi.GetTitle;
		artist := pi.GetArtist;
		SystemLog(titel + '-' + artist);
    idx := idx + 1;
  end;
end;

Läßt Du abgespielte Elemente anzeigen? Die sollten mitzählen. Setze probeweise die Anzahl der gespielten Elemente auf null. Möglicherweise könntest Du von playlist_count den Wert CurrentPlaylist.GetHistoryCount abziehen. (Ist aber in die Bläue hinein, ich kann gerade nichts ausprobieren.)

Nein, diese werden in den Papierkorb verschoben.

Ich könnte mir vorstellen, daß zum Zeitpunkt der „Player Stop“-Operation der Titel ja noch im Player (und damit in der Playlist) ist und erst danach daraus entfernt wird. Setze mal Sleep(100); in die erste Zeile.

Ja, irgend so ein Timing Problem halt.

Damit habe ich in der Zwischenzeit schon experimentiert.
Und es geht damit in der Tat.
Problem ist halt immer bei solchen ‘Kunstgriffen’ man weiß nie wie lange die funktionieren :slight_smile:

Vielleicht fällt @Torben ja noch eine andere Lösung ein.

Warum willst Du das als „Kunstgriff“ bezeichnen? Und warum sollte das irgendwann nicht mehr funktionieren? :thinking:

Nunja, man zwingt ja den aktuellen Thread zum warten.
Nun kenn ich natürlich nicht die Implementierungen in Mairlist, aber ‘auf etwas warten’ kann schon hin und wieder unerwünschte Nebeneffekte mit sich bringen.

Daher versuche ich so etwas meist bei der Programmierung zu vermeiden.

Klar, es handelt sich hier nur um ein paar Millisekunden.

Da ist korrekt. Die Benachrichtigung geht gleichzeitig an das Script wie auch an den Verarbeitungsthread der Playlist, der den Player dann entlädt und ggf. neu belegt. Was davon zuerst passiert, ist mehr oder weniger Zufall.

Wenn du darauf wartest, dass das gerade gestoppte Element aus der Playlist entfernt wurde, könntest du das zum Beispiel in einer Schleife tun:

while CurrentPlaylist.Contains(Item) do Sleep(100);

Nur Vorsicht, auch das Pausieren des Players löst OnPlayerStop aus, und dann bleibt das Element in der Playlist stehen, und das Script landet in einer Endlosschleife. Um diesen Fall abzufangen, wäre es sinnvoll, einen Zähler mit in o.g. Schleife einzubauen, und nach x Runden abzubrechen.

2 Likes

Was jetzt in meinen Augen eher nach „Kunstgriff“ aussieht. :grin:

Aber @ssnoopy, Du könntest natürlich das Argument von Sleep schrittweise verkleinern, bis es eben noch zuverlässig funktioniert, falls Dir eine Zehntelsekunde zu lang ist. Ich bin sicher, da geht noch was. :wink:

Stimme ich zu :slight_smile:
Dann bleib ich wohl doch lieber beim Sleep.

Algorithmen zur Vermeidung von Synchronisationsproblemen bei Nebenläufigkeit sind immer in irgendeiner Weise “Kunstgriff”. Da gibt es ganze Bücher drüber.

Das hier gezeigte “busy waiting” ist ein Standard-Pattern, nicht fürchterlich effizient, aber allgemein als Methode anerkannt.

Natürlich kann auch ein einfaches Sleep in diesem Fall ausreichend sein - aber ein Wort der Warnung: Es gibt auf keine Garantie, in welcher Zeit die Verarbeitung der Playlist abgeschlossen ist. Du musst also selbst die für dich passende Anzahl Millisekunden ermitteln; und selbst dann kann es vorkommen, dass es im Einzelfall mal länger dauert.

Daher ist ein Algorithmus, der explizitig auf das Verschwinden des Elementes aus der Playlist wartet, die einzige wasserdichte Methode.

2 Likes

Danke, Torben, für diese Erklärung. Das ist natürlich richtig, aber ich denke, daß @ssnoopy mit der Routine keinen Reaktor-SCRAM o. ä. auslösen möchte. Daher sah ich den Einzeiler, der einerseits wohl hinreichend lang, andererseits aber auch kurz genug für ssnoopys Belange ist, vorzuschlagen. :slightly_smiling_face:

Aber alles in allem wieder einmal ein lehrreicher Einblick in die Arbeit des Programmierens!

Ich wollte eigentlich immer bei einem Titel von Kraftwerk

Jup, aber du hast schon Recht :wink:

1 Like
procedure OnPlayerStateChange(PlaylistIndex: integer; PlayerIndex: integer; 
  OldState: TPlayerState; NewState: TPlayerState; Item: IPlaylistItem);
begin
  if NewState = psPlaying then
  begin
    if Item.GetArtist = 'Kraftwerk' then
      // usw.

:grin:

2 Likes