Entwickler-Ecke

Internet / Netzwerk - Audio daten senden mit SendBuf / ReceiveBuf


Killmag10 - So 08.07.07 16:00
Titel: Audio daten senden mit SendBuf / ReceiveBuf
Hi

ich versuche mit einen TServerSocket und TClientSocket raw audiodaten zu senden, jedoch kommt dabei nur schrott an.

weis jehmand worans liegen könnte ?

mfg. Killmag10


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  i,l   :integer;
  data  :Pointer;
  n     :integer;
  value :TMemoryStream;
  wert  :smallint;
begin


l:=socket.ReceiveLength;
getmem(data,l);

try
Socket.ReceiveBuf(data^,l-1);
except
ListBox1.Items.Add('Fehler !');
AudioIn1.StopGracefully;
end;


pb1.Position:=0;

N := l Div 2;

value:=TMemoryStream.Create;
value.SetSize(l);
value.Seek(0,soFromBeginning);
value.Write(data,l);
value.Seek(0,soFromBeginning);

for i:=0 to N-2 do
    begin

    value.Read(wert,2);

    if pb1.Position<trunc(wert/(32767/100)) then pb1.Position:=trunc(wert/(32767/100));

    end;

freemem(data);

end;


function TForm1.AudioIn1BufferFilled(Buffer: PChar;
  var Size: Integer): Boolean;
var
  n,i   :integer;
  p     :^smallint;
  value :smallint;
begin

balken1.Position:=0;
client.Address:='127.0.0.1';
client.Port:=portnummer;
client.Open;
Application.ProcessMessages;
balken1.Position:=30;
Client.Socket.SendBuf(Buffer,size);
Application.ProcessMessages;
client.Close;
balken1.Position:=90;



pb2.Position:=0;

N := Size Div 2;
p := Pointer(Buffer);

for i:=0 to N-1 do
    begin
    value:=p^;
    inc(p);

    if pb2.Position<trunc(value/(32767/100)) then begin
       pb2.Position:=trunc(value/(32767/100));
       Label1.Caption:=inttostr(trunc(value/(32767/100)));
    end;

end;

Result:=true;
end;


Narses - So 08.07.07 16:21

Moin!

Dein Code kann so nicht funktionieren, du wertest z.B. gar nicht die Anzahl der gelesenen Bytes aus. :mahn: Siehe FAQ-Beitrag [http://www.delphi-library.de/topic_Warum+gibt+es+kein+ReceiveStream+bei+den+Sockets_65367.html]

Schau dir mal diese Kompos [http://www.delphi-forum.de/topic_TNBFPA+v108++SocketKompos+mit+Protokollfunktionen_71223.html] an, damit ist das sicher einfacher, wenn es ereignisorientiert sein soll. :idea:

cu
Narses


Killmag10 - Mo 09.07.07 01:08

Zitat:
Dein Code kann so nicht funktionieren, du wertest z.B. gar nicht die Anzahl der gelesenen Bytes aus. Siehe FAQ-Beitrag


doch kann aber nur unter gewissen umständen, habs aber natürlich geändert

der eigendliche fehler wahr jedoch


Delphi-Quelltext
1:
Client.Socket.SendBuf(Buffer,size);                    


muss in


Delphi-Quelltext
1:
Client.Socket.SendBuf(Buffer^,size);                    


geändert werden, weil ein pointer allein nütz den andern nicht viel ^^


Narses - Mo 09.07.07 14:41

Moin!

BTW:
user profile iconKillmag10 hat folgendes geschrieben:

Delphi-Quelltext
1:
AudioIn1.StopGracefully;                    

Was´n das für eine spannende Kompo? ;)

user profile iconKillmag10 hat folgendes geschrieben:
doch kann

Schon klar, eigener unsauberer Code ist immer ein ganz kleines bischen sauberer, als fremder... :zwinker:

user profile iconKillmag10 hat folgendes geschrieben:
aber nur unter gewissen umständen,

Yip, unter anderem, weil du raw stream open end data sendest. :mahn: Allerdings, wenn die Samples nicht genau 1 Byte groß sind, produzierst du durch einen Versatz von einem Byte beim Senden/Empfangen wieder Schrott... :?

user profile iconKillmag10 hat folgendes geschrieben:
habs aber natürlich geändert

Wenn du schon dabei bist, dann hätte ich auch noch diese Vorschläge zu machen: ;)

Du erzeugst einen MemoryStream:

Delphi-Quelltext
1:
value :TMemoryStream;                    

aber gibst ihn nicht wieder frei! :shock:

Hier holst du Speicher, den du zwar wenigstens wieder freigibst, aber das ganze machst du viel zu oft:

Delphi-Quelltext
1:
2:
3:
4:
l:=socket.ReceiveLength;  
getmem(data,l);  
//...
freemem(data);

Bei jedem Ereignis wird wieder Speicher angefordert und freigegeben, das zerstückelt dir auf Dauer auch den Heap! :mahn: Anstatt auch noch einen Memorystream anzulegen, bietet es sich an, einen globalen Empfangspuffer zu verwenden (mehr als 8kb kommen ja nie auf einmal an!) und die Werte daraus direkt zu verarbeiten. Das darf dann auch gerne ein Stream sein, dann hast du auch die Möglichkeit, die Daten zu queuen. :idea:

Du liest immer ein Byte zu wenig: :nixweiss:

Delphi-Quelltext
1:
Socket.ReceiveBuf(data^,l-1);                    


Das hier ist potenziell defekter Code: :hair:

Delphi-Quelltext
1:
2:
3:
4:
5:
client.Open;
Application.ProcessMessages;
Client.Socket.SendBuf(Buffer,size);
Application.ProcessMessages;
client.Close;

Grund: Niemand garantiert, dass der Socket nach dem Open und ("nur") dem folgenden MessageLoopCall tatsächlich schon connected ist, damit der Send-Call erfolgreich ist (besonders nicht über´s Internet; lokal mag das ja noch gehen... ist aber trotzdem ein übler Hack)! Du musst (im non-blocking-mode) auf das OnClientConnect-Ereignis warten, wenn du nicht mit "zufällig" auftretenden Exceptions kämpfen willst! :mahn: Das gleiche nach dem Senden: "nur" ein MessageLoopCall mag bei lokalen Transfers (also nicht zu einem anderen System per Netzwerk, sondern zu localhost) ja gerade so noch laufen, der folgende .Close auf den Socket wird dir aber bei einem Internetransfer sicher mal einen solchen kaputt machen... :| Fazit: du behandelst den Socket im non-blocking-mode wie einen im blocking-mode, aber das macht man dann bitte auch in diesem Mode und in einem Thread; alles andere ist kaputt. :roll: :?

cu
Narses


Killmag10 - Mo 09.07.07 18:41

Das war blos ein stück test code :wink:

türlich pass ich auf das der speicher auch wieder freigegeben wird blos hatte ich gerade getestet woran es liegen könnte und hatte beim posten vergessen das wieder rein zu nehmen. :oops: