AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Musik Player Synchronisation
Thema durchsuchen
Ansicht
Themen-Optionen

Musik Player Synchronisation

Ein Thema von DelphiXE · begonnen am 2. Jan 2018
Antwort Antwort
DelphiXE

Registriert seit: 1. Nov 2015
5 Beiträge
 
#1

Musik Player Synchronisation

  Alt 2. Jan 2018, 17:24
Hallo liebe Community,

ich habe in den vergangenen Tagen an einem Kleinen Projekt gearbeitet (Veröffentlichung soll folgen).
Dabei geht es darum eine Anzahl n an Clients die alle einen MusikPlayer (momentan noch Standardkomponente) enthalten über das Netzwerk synchron angesteuert werden. Dabei stellt sich folgendes Problem. In dem Anwendungsbereich sind die Endgräte (meist Android-Geräte) über ein Wlan-Netzwerk mit dem Server verbunden (alles lokal). Die Latenzzeit ist deshalb sehr unterschiedlich. Nun muss ich diese also ermitteln und dann die richtigen Verzögerungen berechnen. Das Problem ist, mit einem Client (und einem Server, der kann auch einen MusikPlayer enthalten) ist das vermutlich noch relativ einfach.

Verfahren:

1.) Latenzzeit ermitteln
Über eine Benachrichtigung über TCP Laufzeit Server->Client->Server ermitteln und durch zwei dividieren.
2.) sleep nach dem Senden von Synchronisationssignal einfügen und Server-MusikPlayer erst nach dem ablaufen der Latenzzeit auf Play setzen.

Dieses Verfahren (nicht ausprobiert, da nur Lösung für Spezialfall) ist jedoch für mehr als einen Client hinfällig, da ich dann noch die Laufzeit für das senden der Netzwerk Informationen wissen müsste und die auch schwankt. Außerdem müsste ich evtl. auch Sachen versetzt starten, obwohl noch kein vollständiger Durchlauf des Datensendens erfolgt ist.

Ich hoffe mein Problem ist verständlich, unten sind die gekürzten Quelltexte zu finden, im Anhang die beiden Projekte (Server und Client)

Grüße und jetzt schon Danke für Hilfe
DelphiXE

Server:
Delphi-Quellcode:
type
  Tvolumedata=record
    funktion: string;
    lied:boolean;
    fulltime:integer;
    part:single;
    position:integer;
  end;
  TGroup=record
    Name:string;
    devicesIndex: Array of Integer;
    music: Array of String;
  end;
  TDevice = record
    Name:string;
    deviceIP: string;
    ABinding: TIdSocketHandle;
    Context: TIdContext;
  end;

var
  Form1: TForm1;
  clients: integer;
  current_play:integer;
  volumedata: array of TVolumedata;
  groups: array of TGroup;
  devices: array of TDevice;

implementation

{$R *.fmx}
{$R *.Windows.fmx MSWINDOWS}

procedure TForm1.Button2Click(Sender: TObject);
var i:integer;
begin
  if (current_play=-1) or (MediaPlayer1.Media=nil) then
      begin
        if Listbox2.Count>0 then
          begin
            if current_play=-1 then
              current_play := current_play+1;
            MediaPlayer1.FileName:=Listbox2.Items[current_play];
            ShowMessage(Listbox2.Items[current_play]);
            ListBox2.ItemIndex:=current_play;
            for I := Low(groups[ListBox3.ItemIndex].devicesIndex) to High(groups[ListBox3.ItemIndex].devicesIndex) do
              begin
                if devices[groups[ListBox3.ItemIndex].devicesIndex[i]].Context<>nil then
                  begin
                    with devices[groups[ListBox3.ItemIndex].devicesIndex[i]].Context.Connection.IOHandler do
                      begin
                        WriteLn('MUSIC_PLAY');
                        {WriteLn(volumedata[ListBox3.ItemIndex].funktion);
                        WriteLn(booltostr(volumedata[ListBox3.ItemIndex].lied));
                        WriteLn(inttostr(volumedata[ListBox3.ItemIndex].fulltime));
                        WriteLn(floattostr(volumedata[ListBox3.ItemIndex].part));
                        WriteLn(inttostr(volumedata[ListBox3.ItemIndex].position));   }

                        WriteLn(inttostr(current_play));
                        sleep(100);
                      end;
                  end;
              end;
          end;
      end;
  MediaPlayer1.Play;
end;

procedure TForm1.Button6Click(Sender: TObject);
var
  I: Integer; AStream: TFileStream;
begin
  OpenDialog1.Execute;
  setLength(groups[ListBox3.ItemIndex].music, High(groups[ListBox3.ItemIndex].music)+2);
  groups[ListBox3.ItemIndex].music[High(groups[ListBox3.ItemIndex].music)]:=Opendialog1.FileName;
  ListBox2.Items.Add(OpenDialog1.FileName);
  for I := Low(groups[ListBox3.ItemIndex].devicesIndex) to High(groups[ListBox3.ItemIndex].devicesIndex) do
    begin
      if devices[groups[ListBox3.ItemIndex].devicesIndex[i]].Context<>nil then
        begin
          AStream:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead + fmShareDenyNone);
          with devices[groups[ListBox3.ItemIndex].devicesIndex[i]].Context.Connection.IOHandler do
            begin
              LargeStream:=true;
              SendBufferSize := 32768;
              WriteLn('MUSIC_FILE');
              WriteLn(ExtractFilename(OpenDialog1.Filename));
              WriteLn(IntToStr(AStream.Size));
              Write(AStream);
            end;
          FreeAndNil(AStream);
        //devices[groups[ListBox3.ItemIndex].devicesIndex[i]].Context.Connection.IOHandler.WriteFile(Opendialog1.FileName, true);
      //devices[groups[ListBox3.ItemIndex].devicesIndex[i]].ABinding.Send
        end;
    end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //-----Gruppen--------//
  setlength(groups, 2);
  groups[0].Name:='Lokale Gruppe';
  setlength(groups[0].devicesIndex, 1);
  groups[0].devicesIndex[0]:=0;
  groups[1].Name:='Test Gruppe';
  setlength(groups[1].devicesIndex, 1);
  groups[1].devicesIndex[0]:=5;
  group_refresh;

  //--------Geräte---------//
  setlength(devices, 1);
  devices[0].Name:='Server';
  devices[0].deviceIP:=IdIPWatch1.LocalIP;
  device_refresh;

  Listbox1.ItemIndex:=0;
  Listbox4.ItemIndex:=0;
  Listbox5.ItemIndex:=0;
  ListBox3.ItemIndex:=0;
  ListBox5ItemClick(self.ListBox5, ListBox5.ItemByIndex(ListBox5.ItemIndex));


  //------------Lautstärke---------//
  setlength(volumedata, 2);
  volumedata[0].funktion:='1';
  volumedata[0].lied:=false;
  volumedata[0].fulltime:=100;
  volumedata[0].part:=50;

  volumedata[1].funktion:='x';
  volumedata[1].lied:=false;
  volumedata[1].fulltime:=100;
  volumedata[1].part:=50;

  clients:=1;
  current_play:=-1;
  IdTCPServer1.Bindings.Add.IP := '127.0.0.1';
  IdTCPServer1.Bindings.Add.Port := 50000;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
  I: Integer;
begin
  for I := Low(devices) to High(devices) do
    begin
      if devices[i].ABinding<>nil then
        if (devices[i].ABinding.PeerIP=AContext.Binding.PeerIP) then
          begin
            devices[i].Context:=AContext;
            Memo1.Lines.Add('test');
          end;
    end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var text:string;
begin
  Memo1.Lines.Add(AContext.Connection.IOHandler.ReadLn);
  AContext.Connection.IOHandler.WriteLn('MUSIC_LATENZ');
end;

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var RecText: string;
  i, k, l: Integer;
  j: Integer;
begin
  recText:=BytesToString(AData);
  memo1.lines.Add(recText);
  if (recText = 'Client') then
    begin
      ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, IdIPWatch1.LocalIP, ABinding.IPVersion);
      setlength(devices, High(devices)+2);
      devices[High(devices)].Name:='Client '+inttostr(clients);
      devices[High(devices)].deviceIP:=ABinding.PeerIP;
      devices[High(devices)].ABinding:=ABinding;
      device_refresh;
      clients:=clients+1;
      Memo1.Lines.Add(devices[High(devices)].ABinding.PeerIP);
    end;
  if (recText = 'Disconnect') then
    begin
      for i := Low(devices) to High(devices) do
        begin
          if devices[i].ABinding=ABinding then
            begin
              for j := i+1 to High(devices) do
                devices[j-1]:=devices[j];
              setlength(devices, High(devices));

              for j := Low(groups) to High(groups) do
                for k := Low(groups[j].devicesIndex) to High(groups[j].devicesIndex) do
                  if groups[j].devicesIndex[k]=i then
                    begin
                      for l := k+1 to High(groups[j].devicesIndex) do
                        groups[j].devicesIndex[l-1]:=groups[j].devicesIndex[l];
                      setlength(groups[j].devicesIndex, High(groups[j].devicesIndex));
                    end;
            end;
        end;
      device_refresh();
      group_refresh();
      ListBox5ItemClick(self.ListBox5, ListBox5.ItemByIndex(ListBox5.ItemIndex));
      ListBox3ItemClick(self.ListBox3, ListBox3.ItemByIndex(ListBox3.ItemIndex));
      dec(clients);
    end;
end;

procedure TForm1.Timer12Timer(Sender: TObject);
begin
if Form1<>nil then
begin
  if (MediaPlayer1.CurrentTime = MediaPlayer1.Duration) and (Mediaplayer1.Media<>nil) then
    begin
      MediaPlayer1.Stop;
      if Listbox2.Count>=current_play+2 then
        begin
          current_play := current_play+1;
          MediaPlayer1.FileName:=Listbox2.Items[current_play];
          ListBox2.ItemIndex:=current_play;
        end
      else
        begin
          if Listbox2.Count>0 then
            begin
              current_play := 0;
              MediaPlayer1.FileName:=Listbox2.Items[current_play];
              ListBox2.ItemIndex:=current_play;
            end
        end;
      MediaPlayer1.Play;
    end
  else
    begin
      if volumedata[ListBox3.ItemIndex].lied=true then
        begin
          MediaPlayer1.Volume:=termtoreal(volumedata[ListBox3.ItemIndex].funktion, MediaPlayer1.CurrentTime/(MediaPlayer1.Duration*volumedata[ListBox3.ItemIndex].part*0.01));
          if IsNaN(100-(termtoreal(volumedata[ListBox3.ItemIndex].funktion, MediaPlayer1.CurrentTime/(MediaPlayer1.Duration*volumedata[ListBox3.ItemIndex].part*0.01)*100)))<>true then
            TrackBar1.Value:=100-(termtoreal(volumedata[ListBox3.ItemIndex].funktion, MediaPlayer1.CurrentTime/(MediaPlayer1.Duration*volumedata[ListBox3.ItemIndex].part*0.01))*100)
          else
            TrackBar1.Value:=50;
         { Memo1.Lines.Clear;
          Memo1.Lines.add(floattostr(MediaPlayer1.Volume));
          Memo1.Lines.add(floattostr((MediaPlayer1.Duration*volumedata[ListBox3.ItemIndex].part*0.01)));
          Memo1.Lines.add(floattostr(MediaPlayer1.CurrentTime));   }

        end
      else
        begin
          if (volumedata[ListBox3.ItemIndex].lied=false) and (MediaPlayer1.State = TMediaState.Playing) then
            volumedata[ListBox3.ItemIndex].position:=volumedata[ListBox3.ItemIndex].position+1;
          if volumedata[ListBox3.ItemIndex].position>volumedata[ListBox3.ItemIndex].fulltime*10 then
            volumedata[ListBox3.ItemIndex].position:=0;

          MediaPlayer1.Volume:=termtoreal(volumedata[ListBox3.ItemIndex].funktion, 1/volumedata[ListBox3.ItemIndex].part*volumedata[ListBox3.ItemIndex].position*0.1);
          if IsNaN(100-(termtoreal(volumedata[ListBox3.ItemIndex].funktion, 1/volumedata[ListBox3.ItemIndex].part*volumedata[ListBox3.ItemIndex].position*0.1)*100))<>true then
            TrackBar1.Value:=100-(termtoreal(volumedata[ListBox3.ItemIndex].funktion, 1/volumedata[ListBox3.ItemIndex].part*volumedata[ListBox3.ItemIndex].position*0.1)*100)
          else
            TrackBar1.Value:=50;
         { Memo1.Lines.Clear;
          Memo1.Lines.add(floattostr(MediaPlayer1.Volume));
          Memo1.Lines.add(floattostr(1/volumedata[ListBox3.ItemIndex].part*(MediaPlayer1.CurrentTime*0.0000001)));
          Memo1.Lines.add(floattostr(roundto(volumedata[ListBox3.ItemIndex].position,-1)));         }

        end;
    end;
end;
end;

end.
Client:
Delphi-Quellcode:
type
  Tvolumedata=record
    funktion: string;
    lied:boolean;
    fulltime:integer;
    part:single;
    position:integer;
  end;

var
  Form1: TForm1;
  count: Integer;
  volumedata: TVolumedata;
  current_play:integer;
  files: Array of string;

implementation

{$R *.fmx}
{$R *.LgXhdpiPh.fmx ANDROID}

procedure TForm1.Button1Click(Sender: TObject);
begin
  idTCPClient1.Host:=Edit1.Text;
  idTCPClient1.Port:=50000;
  IdTCPClient1.Connect;
  IdTCPClient1.IOHandler.WriteLn('Test1');
end;

procedure TForm1.Button2Click(Sender: TObject);
var rec: TIdBytes;
begin
  setLength(rec, 16);
  UDPClient.Broadcast('Client', 49999);
  UDPClient.ReceiveBuffer(rec, 1000);
  Edit1.Text:=BytesToString(rec);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  IdTCPClient1.Disconnect;
  UDPClient.Broadcast('Disconnect', 49999);
end;

procedure TForm1.FormCreate(Sender: TObject);
  var rec: TIdBytes;
begin
  setLength(rec, 16);
  UDPClient.Broadcast('Client', 49999);
  UDPClient.ReceiveBuffer(rec, 1000);
  Edit1.Text:=BytesToString(rec);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var AStream:TFileStream; Filesize:Integer; FileName:string; option: string;
begin
  Application.ProcessMessages;
  if IdTCPClient1.Connected then
  begin
    //if IdTCPClient1.IOHandler.Readable then
    begin
      option:='';
      option:=IdTCPClient1.IOHandler.Readln;
      memo1.Lines.Add(option);
      if option='MUSIC_FILEthen
        begin
          FileName:=IdTCPClient1.IOHandler.ReadLn;
          Filesize:=strtoint(IdTCPClient1.IOHandler.Readln);
          ForceDirectories(ExtractFilePath(Paramstr(0)) + 'In');
          AStream := TFileStream.Create(ExtractFilePath(Paramstr(0))+ 'In\' + FileName, fmCreate);
          IdTCPClient1.IOHandler.RecvBufferSize:= 32768;
          idTCPClient1.ReadTimeout:=-1;
          IdTCPClient1.IOHandler.ReadStream(AStream, FileSize, False);
          idTCPClient1.ReadTimeout:=5;
          setlength(files, high(files)+2);
          files[high(files)]:=ExtractFilePath(Paramstr(0))+ 'In\' + FileName;
          FreeAndNil(AStream);
          inc(count);
        end;
      if option='MUSIC_PLAYthen
        begin
          {Volumedata.funktion:=IdTCPClient1.IOHandler.ReadLn;
          Volumedata.lied:=strtobool(IdTCPClient1.IOHandler.ReadLn);
          Volumedata.fulltime:=strtoint(IdTCPClient1.IOHandler.ReadLn);
          Volumedata.part:=strtofloat(IdTCPClient1.IOHandler.ReadLn);
          Volumedata.position:=strtoint(IdTCPClient1.IOHandler.ReadLn);
          current_play:=strtoint(IdTCPClient1.IOHandler.ReadLn); }

          mediaPlayer1.FileName:=files[current_play];
          MediaPlayer1.Play;
        end;
    end;
  end;
end;
Angehängte Dateien
Dateityp: zip Client_dpn.zip (39,3 KB, 7x aufgerufen)
Dateityp: zip Server_dpn.zip (166,8 KB, 7x aufgerufen)
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:00 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz