|
Registriert seit: 1. Nov 2015 5 Beiträge |
#1
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:
Client:
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.
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_FILE' then 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_PLAY' then 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; |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |