Newsgroup: it.comp.lang.delphi
Titolo: Problema streaming audio - L' ho gia` postato?

CIAO, volevo fare un programma per parlare su internet, ma ho qualche
problemino.. L' audio va a scatti -_-' ho postato anche il source del .pas
almeno vedete che ho combinato.
Vi ringrazio in anticipo, ciao ciao :D
-----------------------------------------
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MmSystem, ScktComp;
type
  TForm1 = class(TForm)
    Start: TButton;
    Stop: TButton;
    Memo1: TMemo;
    ClientSocket1: TClientSocket;
    ServerSocket1: TServerSocket;
    ClientOpen: TButton;
    ServerOpen: TButton;
    procedure Play(Buffer: array of Char; Size: Integer);
    procedure Audio_Initialize;
    procedure StartClick(Sender: TObject);
    procedure StopClick(Sender: TObject);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientOpenClick(Sender: TObject);
    procedure ServerOpenClick(Sender: TObject);
  private
    { Private declarations }
    procedure WaveDoneOut(var Msg: TMessage); message  MM_WOM_DONE;
    procedure WaveOpenIn(var Msg: TMessage); message  MM_WIM_OPEN;
    procedure WaveCloseIn(var Msg: TMessage); message  MM_WIM_CLOSE;
    procedure BufferFinished(var Msg: TMessage); message  MM_WIM_DATA;
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
// In
  Buf: array [0..2048] of Char; // 2 Kb di buffer -_-
  wh: WAVEHDR;
  hWavIn: HWAVEIN;
  wfx: TWaveFormatEx;
// Out
  WavH: WAVEHDR;
  WavOut: HWAVEOUT;
  WavFMT: TWaveFormatEx;
implementation
{$R *.dfm}
procedure TForm1.WaveOpenIn(var Msg: TMessage);
begin
Memo1.Lines.Add('Wave In Open');
end;
procedure TForm1.WaveCloseIn(var Msg: TMessage);
begin
Memo1.Lines.Add('Wave In Close');
end;
procedure TForm1.WaveDoneOut(var Msg: TMessage);
begin
Memo1.Lines.Add('Wave out done.');
// chiusura dell' output
waveOutReset(WavOut);
waveOutUnprepareHeader(WavOut, @WavH, sizeof(WavH));
waveOutClose(WavOut);
//
end;
procedure TForm1.Play(Buffer: array of Char; Size: Integer);
begin
// inizializzazione del buffer
WavH.lpData:= Buffer;
WavH.dwBufferLength := Size;
//
// inizializzazione del formato wave a 11 kHz  8 bit mono PCM
WavFMT.wFormatTag := WAVE_FORMAT_PCM;
WavFMT.nChannels := 1;
WavFMT.nSamplesPerSec := 11025;
WavFMT.wBitsPerSample := 8;
WavFMT.nBlockAlign := WavFMT.nChannels * (WavFMT.wBitsPerSample div 8) ;
WavFMT.nAvgBytesPerSec := (WavFMT.nSamplesPerSec * WavFMT.nBlockAlign);
WavFMT.cbSize := 0;
//
// Riproduce il suono
waveOutOpen(@WavOut, WAVE_MAPPER, @WavFMT, Integer(Self.Handle), 0,
CALLBACK_WINDOW);
waveOutPrepareHeader(WavOut, @WavH, sizeof(WavH));
Memo1.Lines.Add('Wave out Play.');
waveOutWrite(WavOut, @WavH, sizeof(WavH));
end;
procedure TForm1.BufferFinished(var Msg: TMessage);
begin
Memo1.Lines.Add('Buffer finito');
//Play(wh.lpData, wh.dwBytesRecorded);  // senza sendare (va` a scatti) -_-
ClientSocket1.Socket.SendBuf(Buf, SizeOf(Buf)); // kakkio va` a scatti  -_-'
waveInAddBuffer(hWavIn, @wh, sizeof(wh)); // dopo il play riusa il buffer
end;
procedure TForm1.Audio_Initialize;
begin
// inizializzazione del buffer
wh.lpData:= Buf;
wh.dwBufferLength := SizeOf(Buf);
//
// inizializzazione del formato wave a 11 kHz  8 bit mono PCM
wfx.wFormatTag := WAVE_FORMAT_PCM;
wfx.nChannels := 1;
wfx.nSamplesPerSec := 11025;
wfx.wBitsPerSample := 8;
wfx.nBlockAlign := wfx.nChannels * (wfx.wBitsPerSample div 8) ;
wfx.nAvgBytesPerSec := (wfx.nSamplesPerSec * wfx.nBlockAlign);
wfx.cbSize := 0;
//
end;
procedure TForm1.StartClick(Sender: TObject);
begin
Audio_Initialize;
// apre il device di input (Wave mapper)
if waveInOpen(@hWavIn, WAVE_MAPPER, @wfx, Integer(Form1.Handle), 0,
CALLBACK_WINDOW) <> MMSYSERR_NOERROR then
   ShowMessage('Errore nell'' apertura.');
//
// prepara il buffer per la registrazione
if waveInPrepareHeader(hWavIn, @wh, sizeof(wh)) <> MMSYSERR_NOERROR then
   ShowMessage('Errore waveInPrepareHeader');
//
// aggiunge il buffer per la registrazione
if waveInAddBuffer(hWavIn, @wh, sizeof(wh)) <> MMSYSERR_NOERROR then
   ShowMessage('Errore waveInAddBuffer');
//
waveInStart(hWavIn);// inizio registrazione
end;
procedure TForm1.StopClick(Sender: TObject);
begin
waveInStop(hWavIn);    // ferma la registrazione
// chiude il buffer di registrazione
if waveInUnprepareHeader(hWavIn, @wh, sizeof(wh)) <> MMSYSERR_NOERROR then
   ShowMessage('Errore waveInUnprepareHeader');
//
waveInClose(hWavIn);   // chiude il device audio
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
Buffo: array [0..2048] of char;
begin
Socket.ReceiveBuf(Buffo, SizeOf(Buffo));
Play(Buffo, SizeOf(Buffo));
end;
procedure TForm1.ClientOpenClick(Sender: TObject);
begin
ClientSocket1.Open;
end;
procedure TForm1.ServerOpenClick(Sender: TObject);
begin
ServerSocket1.Open;
end;
end.
............................................................................
.....

 Vi ringrazio in anticipo, ciao ciao :D
A 11KHz, 8 bit, su internet ci andrai sempre a scatti.
Chi te li dà 88 Kbit di banda, Babbo Natale ? :)
A parte questo, anche su LAN, l'algoritmo che usi
parte dal presupposto che i clock dei 2 PC siano
identici e che non ci sia jitter (i pacchetti arrivano
ogni tot ms, precisi al millesimo). Queste 2 ipotesi
non si verificano.
Come minimo devi bufferizzare, il pacchetto che arriva
adesso dalla LAN non puoi riprodurlo subito ma deve andare
in play dopo un po', mentre nel frattempo viene riprodotto
il pacchetto precedente. Se mandi in riproduzione pacchetti
da 2 Kbyte (scelta infelice perché non ci stanno in un unico
pacchetto ethernet), il buffer audio deve essere almeno di
4 Kbyte, così mentre scrivi nella parte alta viene riprodotta
la parte bassa e viceversa.
Con questo sistemi il jitter. Per la differenza di clock,
ci risentiamo. :)
Ciao,
--
Il Cammelliere
http://it.geocities.com/ilcammelliere

> Il Cammelliere
Ehm... Forse era meglio che scrivevo anche che sono un novellino...
Ho comprato delphi 4 standard nel '99 ma poi ho mollato e ho ripreso 2 o 3
mesi fa` con il 6 personal,
quindi sono un po` (molto) ignorante, me lo puoi rispiegare ?
Che sono i clock e i jitter ?

 ha scritto nel
messaggio news:tBsf9.7774$Oz2.1...@twister2.libero.it...

Per clock intendo il clock della scheda sonora, la velocità
con cui i campioni vengono catturati e riprodotti. Quando
imposti la velocità a 11025 campioni al secondo su 2 PC,
non è vero che andranno entrambi a tale velocità. Uno sarà
più veloce dell'altro per cui catturerà più campioni di
quanti l'altro non ne riproduca nello stesso tempo.
Il problema opposto nel verso contrario. In un verso
mancano i campioni, nell'altro avanzano. Devi inventarti
qualcosa per farli viaggiare in parallelo, dalla semplice
duplicazione/eliminazione dei campioni all'interpolazione...
Per jitter intendo la deriva temporale che c'è tra un
pacchetto e l'altro. La notifica che un buffer audio
è pieno non arriva ad intervalli regolari. C'è una
tolleranza legata a vari fattori tra cui la velocità
della CPU, il SW che sta girando in background, etc.
Se un buffer deve essere pronto ogni 100 ms, nessuno te
lo garantisce: il secondo arriverà dopo 90, il terzo dopo
140, poi 105, 86,... Devi metterti al riparo dal fatto che
un pacchetto potrebbe ancora non essere arrivato quando
è arrivato il momento di riprodurlo. Se esageri con la
bufferizzazione introduci un ritardo esagerato; se scarseggi,
senti le pernacchie.
