请问为什么用ICS的WSocket、UDP方式发送字符串没问题,而发二进制就有问题?(100分)

  • 主题发起人 主题发起人 hq_pan
  • 开始时间 开始时间
H

hq_pan

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用了 ICS 套件种的 TWSocket 控件,协议方式为 UDP.
测试是发送字符串句没问题,但是发送二进制,接收就有问题!!!
我使用 ACM 获取语音输入,然后通过 UDP 方式发送出去,
接收后播放是刺耳的声音,而不是话筒输入的声音。如果不通过
网络发送,而直接播放话筒输入的声音就没问题。我已经用过
了 Indy 的控件,下载的源代码用的是 NMUDP。下载的代码
运行的好好的,换了ICS/Indy就不行了,请我是不是我服务器端
接收的代码有错啊?我用二进制方式传送字符串,接收过来
却是正确的。
请高手帮帮忙!!!明天就要检查了...[:(!]
分不是问题,手上还有几千分。
================================================================================
unit uMainFrm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, WSocket, WinSock, ACMIn, ACMOut, ACMConvertor, ExtCtrls;

type
TForm1 = class(TForm)
edtRmtIP: TEdit;
btnStart: TButton;
btnStop: TButton;
Memo1: TMemo;
UDPSrv: TWSocket;
UDPCli: TWSocket;
Label1: TLabel;
Label2: TLabel;
edtRmtPort: TEdit;
btnSend: TButton;
Splitter1: TSplitter;
btnStartWave: TButton;
btnStopWave: TButton;
UDPWaveCli: TWSocket;
UDPWaveSrv: TWSocket;
ACMOut1: TACMOut;
ACMIn1: TACMIn;
ACMConvertor1: TACMConvertor;
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure UDPSrvDataAvailable(Sender: TObject; ErrCode: Word);
procedure FormCreate(Sender: TObject);
procedure btnSendClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure btnStartWaveClick(Sender: TObject);
procedure btnStopWaveClick(Sender: TObject);
procedure UDPWaveSrvDataAvailable(Sender: TObject; ErrCode: Word);
procedure ACMIn1BufferFull(Sender: TObject; Data: Pointer;
Size: Integer);
private
{ Private declarations }
//FBufSize: Longint;
public
{ Public declarations }
procedure prcToggleBtnState(Start: Boolean);
procedure prcTglWaveBtn(const ToStart: Boolean);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

const
SrvPort = '2828';
SockType = 'UDP';

procedure TForm1.prcToggleBtnState(Start: Boolean);
begin
btnStart.Enabled := Start;
btnStop.Enabled := not Start;
end;

procedure TForm1.prcTglWaveBtn(const ToStart: Boolean);
begin
btnStartWave.Enabled := ToStart;
btnStopWave.Enabled := not ToStart;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
edtRmtPort.Text := SrvPort;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UDPSrv.Close;
end;

procedure TForm1.btnStartClick(Sender: TObject);
begin
UDPCli.Close;
UDPSrv.Proto := SockType;
UDPSrv.Addr := '0.0.0.0';
UDPSrv.Port := edtRmtPort.Text;
//UDPSrv.BufSize := ACMConvertor1.InputBufferSize;
UDPSrv.Listen;
prcToggleBtnState(False);
Memo1.Lines.Add('Server start at ' + DateTimeToStr(Now));
end;

procedure TForm1.btnStopClick(Sender: TObject);
begin
UDPSrv.Close;
prcToggleBtnState(True);
Memo1.Lines.Add('Server stop at ' + DateTimeToStr(Now));
end;

procedure TForm1.UDPSrvDataAvailable(Sender: TObject; ErrCode: Word);
var
Buffer : PChar; // ; Pointer array [0..8192] of char
Bufsize: integer;
Len : Integer;
//Src : TSockAddrIn;
//SrcLen : Integer;
begin
Memo1.Lines.Add('Recieved data at ' + DateTimeToStr(Now));
Bufsize := 1024;
Getmem(Buffer, Bufsize);
Len := 0;
try
try
Len := UDPSrv.Receive(Buffer, Bufsize);// SizeOf(Buffer)
except
Memo1.Lines.Add('Reciev error!');
end;
try
Memo1.Lines.Add('Recieved data length: ' + IntToStr(Len));
except
Memo1.Lines.Add('Show reciev data length error!');
end;

if Len > 0 then
begin
Buffer[Len] := #0;
Memo1.Lines.Add('================');
Memo1.Lines.Add(StrPas(Buffer));
Memo1.Lines.Add('================');
end;
finally
FreeMem(Buffer);
Memo1.Lines.Add('Finally FreeMem.');
end;
//Len := UDPSrv.LastError;
Memo1.Lines.Add('Last error code: ' + IntToStr(UDPSrv.LastError)
+ #13#10'ErrCode: ' + IntToStr(ErrCode));
Memo1.Lines.Add('Recieved data finished.');
end;

procedure TForm1.btnSendClick(Sender: TObject);
var
data: Pointer;
s: string;
sl: integer;
begin
Memo1.Lines.Add('Sending data out: ' + DateTimeToStr(Now));
//GetMem(data, Length(Memo1.Lines[1]));
s := Memo1.Lines[1];
data := @s[1];
UDPCli.Proto := SockType;
UDPCli.Addr := edtRmtIP.Text;
UDPCli.Port := edtRmtPort.Text;
UDPCli.LocalPort := '0';
UDPCli.Connect;
sl := UDPCli.Send(data, Length(s));
UDPCli.Close;
if sl = -1 then
begin
Memo1.Lines.Add('Last Error code: ' + IntToStr(UDPCli.LastError));
exit;
end;
Memo1.Lines.Add('Sending data finished: ' + DateTimeToStr(Now));
end;

//------------------------------------------------------------------------------
procedure TForm1.btnStartWaveClick(Sender: TObject);
begin
ACMOut1.Open(ACMConvertor1.FormatIn);
UDPWaveCli.Close;
UDPWaveSrv.Proto := SockType;
UDPWaveSrv.Addr := '0.0.0.0';
UDPWaveSrv.Port := edtRmtPort.Text;
//UDPSrv.BufSize := ACMConvertor1.InputBufferSize;
UDPWaveSrv.Listen;
prcTglWaveBtn(False);

ACMIn1.Open(ACMConvertor1.FormatIn);

Memo1.Lines.Add('Wave Server started at ' + DateTimeToStr(Now));
end;

procedure TForm1.btnStopWaveClick(Sender: TObject);
begin
ACMIn1.Close;
UDPWaveSrv.Close;
ACMOut1.Close;
prcTglWaveBtn(True);
Memo1.Lines.Add('Wave Server stop at ' + DateTimeToStr(Now));
end;

procedure TForm1.UDPWaveSrvDataAvailable(Sender: TObject; ErrCode: Word);
var
Buffer : PChar;
Bufsize: integer;
Len : Integer;
Src : TSockAddrIn;
SrcLen : Integer;
begin
Bufsize := 8192; //ACMConvertor1.FormatIn.Format.nAvgBytesPerSec + 100;
Getmem(Buffer, Bufsize);
try
Len := UDPWaveSrv.ReceiveFrom(Buffer, Bufsize, Src, SrcLen);
{Memo1.Lines.Add('Recieved data form ' + StrPas(inet_ntoa(Src.sin_addr)) +
':' + IntToStr(ntohs(Src.sin_port)));
Memo1.Lines.Add('Recieved data length: ' + IntToStr(Len));}
if Len > 0 then
begin
ACMOut1.Play(Buffer, Len);
end;
finally
FreeMem(Buffer);
end;
//Memo1.Lines.Add('Recieved data finished.');
end;

procedure TForm1.ACMIn1BufferFull(Sender: TObject; Data: Pointer;
Size: Integer);
begin
UDPWaveCli.Proto := SockType;
UDPWaveCli.Addr := edtRmtIP.Text;
UDPWaveCli.Port := edtRmtPort.Text;
UDPWaveCli.LocalPort := '0';
UDPWaveCli.Connect;
UDPWaveCli.Send(Data, Size);
UDPWaveCli.Close;
//Memo1.Lines.Add('Send wave data at ' + DateTimeToStr(Now));
end;

end.
 
请高手提点一下!!!
 
在线等待!!!
 
sorry, i only know mis and sqlserver.
 
555~~
难道高手现在都潜水了吗?
 
现在又有新情况了:
分开服务器、客户端,传送语音没问题,声音也连续;
合并为一个程序,但是分服务器、客户端两个窗口,
传送也没问题,声音也连续;
合并为一个程序,服务器、客户端同一个窗口,
有两种情况-因为做了两个程序来实验,一个是声音
不连续,常常中间有丢失,一个是收到的根本不成语音。
代码我都是拷贝的。
[:(!][:(!][:(!][:(!][:(!]
上天为什么对我如此残酷????
 
有人能给点意见吗?
 
没人理会吗?
 
换个张无寄兄的UDP组件吧,这个东西老早写过,给你个代码参考一下

// 司马华鹏
//------------------------------------------------------------------------------
// 读取语音数据
procedure TfrmMain.UDPChatDataRead(UDPSocket: TSHUDPSocket;
const PeerInf: TPeerInfo);
var
MData: array[1..10000] of Char;
Data: PChar;
NumberBytes:integer;
begin
//首先要调用RecvBuf函数,再才能调用PeerInf从中得到对方的信息
NumberBytes := UDPSocket.RecvBuf(MData, SizeOf(MData));

Data := PChar(DWord(@MData));
frmVoiceChat.plGet.Caption := '数据包:' + IntToStr(PlayPackets);
Inc(PlayPackets);

if NumberBytes<>-1 then
begin
AcmWaveOut.PlayBack(Data,NumberBytes);
end else
begin
Inc(ErrorPackets);
end;

frmVoiceChat.plErr.Caption := '错误:' + IntToStr(ErrorPackets);
frmVoiceChat.plSize.Caption := '包大小:' + IntToStr(NumberBytes);

frmVoiceChat.ProBar.Position:=Random(100);
end;

//------------------------------------------------------------------------------
// 语音聊天的初始化
function TfrmMain.fcStartVoiceChat: Boolean;
var
Format: Pointer;
Gms: TGms;
begin
Result:=False;
try
UdpChat.Port:=CS_PortVoiceClt;
UdpChat.Active := True;
except
UdpChat.Active := False;
Alert('打开网络套接字出错');
Exit;
end;

with Gms do
begin
wFormatTag := $31;
nChannels := 1;
wBitsPerSample := 0;
nSamplesPerSec := 8000;
nBlockAlign := 65;
nAvgBytesPerSec := 1625;
cbSize := 2;
wSamplesPerBlock := $140;
end;
Format := @Gms;
if Format = nil then Exit;
try
AcmWaveIn.Open(Format);
AcmWaveOut.Open(Format);
PlayPackets:=0;
ErrorPackets:=0;
except
On e:exception do
begin
Alert('初始化音频设备失败:' + e.Message);
Exit;
end;
end;
Result:=True;
end;

//------------------------------------------------------------------------------
// 语音聊天的释放
function TfrmMain.fcStopVoiceChat: Boolean;
begin
Result:=True;
try
AcmWaveIn.Close;
AcmWaveOut.Close;
UdpChat.Active := False;
except
Result:=False;
end;
end;

//------------------------------------------------------------------------------
// 采集到音频数据,则立即送出
procedure TfrmMain.AcmWaveInData(data: Pointer; size: Integer);
var
MData: array[1..10000] of Char;
I: Integer;
begin
for I := 1 to Size do
begin
MData := PChar(DWord(Data) + DWord(I - 1))^;
end;
UDPChat.SendBuf(MData, Size, strHost,CS_PortVoiceSer);
end;

//------------------------------------------------------------------------------
// 停止语音聊天消息
procedure TfrmMain.WMStopVoiceChat(var Msg: TWMSysCommand);
begin
frmVoiceChat.Hide;
if not fcStopVoiceChat then
begin
UDPCommand.SendText('#E' + '关闭音频设备失败!',strHost,Cs_PortServer);
end;
end;
 
说句实话,张无忌兄的UDP组件我已下回来了,但是不知道为什么,
我用它自带的例子,可以编译,但是运行什么效果都没有!

今天我又把自己的程序用New Application 实现了一次,这次居然
成功了!!!语音通话还不错!我都搞不懂自己的机子发生了什么
毛病!偏偏跟我作对。今天新做的app通话不错,但是话筒的声音
却直接回响,而以前的程序运行接管麦克风后一般要延迟才有声音
出来,而现在是相同的声音响了两次:一次是直接回响,没有延迟,
一次是延迟了,应该是通过UDP发送的数据。现在心里很郁闷[:(]

还有,上面的例程只是针对GSM这种格式,换其它格式就会出错。

非常感谢兄台关注这个问题!
 
to :hq_pan我是楚辞前天
你所说的是应该加入到:procedure TForm1.Button3Click(Sender: TObject);
begin


end;
中间是吗?这是在form9表单里做的(form9是我的登录窗体,form3是我的主程序),我试了不行 ,我 到底应该放在哪个事件里?还有我应该放在哪个窗体是form3还是form9?
,请把具体位置指出来!一个菜鸟刚学有很多东西不会!
 
diang~~~
你还能找到这来啊?怎么知道是我啊?
你点击按钮想显示那个form就创建那个form噻。

问题结束算了,莫明奇怪的问题……
 
后退
顶部