Android 播放通过UDP套接字接收的流时出现口吃播放
我想从PC(C++应用程序,使用FMOD-API解码音频数据并通过UDP套接字发送)向android设备发送音频流。通讯已经开始,我可以在android上听到“声音”(100毫秒的声音,接着是900毫秒的静音,交替) 我不知道为什么声音会断断续续——在PC上,同样的音频流播放质量很好。我认为问题出在安卓系统上 代码如下:Android 播放通过UDP套接字接收的流时出现口吃播放,android,sockets,stream,udp,audiotrack,Android,Sockets,Stream,Udp,Audiotrack,我想从PC(C++应用程序,使用FMOD-API解码音频数据并通过UDP套接字发送)向android设备发送音频流。通讯已经开始,我可以在android上听到“声音”(100毫秒的声音,接着是900毫秒的静音,交替) 我不知道为什么声音会断断续续——在PC上,同样的音频流播放质量很好。我认为问题出在安卓系统上 代码如下: DatagramSocket sock = new DatagramSocket(12345); byte []bSockBuffer = new by
DatagramSocket sock = new DatagramSocket(12345);
byte []bSockBuffer = new byte[1024];
byte []bRecvBufTmp;
int iAudioBufSize, iCurAudioBufPos = 0;
sock.setReceiveBufferSize(bSockBuffer.length);
// Audio Stream initialisieren:
iAudioBufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, iAudioBufSize, AudioTrack.MODE_STREAM);
track.play();
while (true)
{
DatagramPacket pack = new DatagramPacket(bSockBuffer, bSockBuffer.length);
// Paket empfangen:
sock.receive(pack);
track.write(pack.getData(), 0, pack.getLength());
}
我确信正确设置“AudioTrar”对象,设置与C++应用程序中的设置相比较。
另一个步骤是在临时“byte[]”变量中预缓冲接收到的套接字数据,并在达到缓冲区“iAudioBufSize”的大小时将其写入AudioTrack对象。
这没有帮助
有什么想法吗?
谢谢
[编辑]
C++应用程序代码,使用FMOD API示例的“手工解码”示例:
FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
{
CCtrlSocket *cClientTmp = /* Obtaining target client sock here */;
FMOD_RESULT result;
unsigned int read, uSentTmp, uSizeTmp;
EnterCriticalSection(&decodecrit);
if (!decodesound)
return (FMOD_ERR_FILE_EOF);
result = decodesound->readData(data, datalen, &read);
if (result == FMOD_ERR_FILE_EOF)
{
// Handle looping:
decodesound->seekData(0);
datalen -= read;
result = decodesound->readData((char*) data + read, datalen, &read);
}
// Split package in multiple parts:
uSentTmp = 0;
do
{
uSizeTmp = (read - uSentTmp);
if (uSizeTmp > 1024)
uSizeTmp = 1024;
uSentTmp += cClientTmp->SendAudioData((char*) data + uSentTmp, uSizeTmp);
} while (uSentTmp < read);
LeaveCriticalSection(&decodecrit);
return (FMOD_OK);
}
FMOD_结果F_回调pcmreadcallback(FMOD_SOUND*SOUND,void*data,unsigned int datalen)
{
CCtrlSocket*cClientTmp=/*在此处获取目标客户端sock*/;
FMOD_结果;
无符号整型读取,uSentTmp,uSizeTmp;
EnterCriticalSection(&decodecrit);
如果(!解码声音)
返回(FMOD\u ERR\u FILE\u EOF);
结果=解码声音->读取数据(数据、数据列和读取);
如果(结果==FMOD\U ERR\U文件\U EOF)
{
//句柄循环:
解码声音->搜索数据(0);
datalen-=读取;
结果=解码声音->读取数据((字符*)数据+读取、数据长度和读取);
}
//将包装拆分为多个部分:
uSentTmp=0;
做
{
uSizeTmp=(read-uSentTmp);
如果(uSizeTmp>1024)
uSizeTmp=1024;
uSentTmp+=cClientTmp->SendAudioData((char*)数据+uSentTmp,uSizeTmp);
}while(uSentTmp
我已经解决了这个问题。
混乱是日志文件中的一个条目,花费了大量时间造成了延迟:(
现在我可以在我的android客户端上听到流式音乐。但是仍然有一些滞后。我已经试验了很多套接字和音轨缓冲区的值。
我比较了发送和接收字节的数量:在20秒内,发送9170000字节的数据会导致在android设备上接收8120000字节。起初,流播放速度很快,持续3秒(这意味着缓冲区已满?)。30秒后,流延迟(这意味着缓冲区已空?)。
总体而言,音乐质量非常好,但始终有嘶嘶声(这表示插座包丢失?)
我的“PlaybackStart()”函数已更改-我不再使用PCM读取回调:
FMOD_RESULT CAudioStream::PlaybackStart()
{
CCtrlSocket *cClientTmp;
unsigned int read, uSentTmp, uSizeTmp;
FMOD_RESULT result;
result = system->createStream("C:\\test.mp3", FMOD_OPENONLY | FMOD_ACCURATETIME, 0, &sound);
if(result != FMOD_OK)
return (result);
int iChannels, iBits;
FMOD_SOUND_FORMAT fFormat;
FMOD_SOUND_TYPE fType;
result = sound->getFormat(&fType, &fFormat, &iChannels, &iBits);
if(result != FMOD_OK)
return (result);
void *data;
unsigned int length = 0;
int iSampleSec = 1; // Playtime
int iSampleSize = (44100 * 2 * sizeof(signed short) * iSampleSec);
int iSleep = 6; // Sleep after sending a package
DWORD dSleepTotal;
result = sound->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
if(result != FMOD_OK)
return (result);
data = malloc(iSampleSize);
if (!data)
return (FMOD_RESULT_FORCEINT);
cClientTmp = (CCtrlSocket*) CCtrlSocket::cServerSock.GetClientSock(CCtrlSocket::cServerSock.GetClientSockCount() - 1);
do
{
result = sound->readData((char*) data, iSampleSize, &read);
if ((result != FMOD_OK) && (result != FMOD_ERR_FILE_EOF))
ASSERT(FALSE);
else if (read > 0)
{
dSleepTotal = 0;
for (int i = 0; i < read; i += NET_SVR_AUDIO_BUFFER)
{
// MIN_VAL_LIMITED ((MIN_VAL(VAL1, VAL2) <= LIMIT) ? LIMIT : MIN_VAL(VAL1, VAL2))
cClientTmp->SendAudioData((char*) data + i, MIN_VAL_LIMITED(NET_SVR_AUDIO_BUFFER, (read - i), 0));
// Sleep after sending every package:
Sleep(iSleep);
dSleepTotal += iSleep;
}
if (dSleepTotal < (iSampleSec * 1000))
{
dSleepTotal = (iSampleSec * 1000) - dSleepTotal;
// Sleep after sending every second playtime:
Sleep(dSleepTotal);
}
}
} while (read > 0);
result = sound->release();
if(result != FMOD_OK)
return (result);
result = system->close();
if(result != FMOD_OK)
return (result);
result = system->release();
if(result != FMOD_OK)
return (result);
return (result);
}
FMOD_结果CAudioStream::PlaybackStart()
{
CCtrlSocket*cClientTmp;
无符号整型读取,uSentTmp,uSizeTmp;
FMOD_结果;
结果=系统->createStream(“C:\\test.mp3”,FMOD_OPENONLY | FMOD_accurrateTime,0,&sound);
如果(结果!=FMOD\U正常)
返回(结果);
国际iChannels,iBits;
FMOD_声音_格式格式格式;
FMOD_声音_类型F类型;
结果=声音->获取格式(&fType,&fFormat,&iChannels,&iBits);
如果(结果!=FMOD\U正常)
返回(结果);
作废*数据;
无符号整数长度=0;
int iSampleSec=1;//播放时间
int iSampleSize=(44100*2*sizeof(签名短)*iSampleSec);
int iSleep=6;//发送包后休眠
德沃德·德雷普托尔;
结果=声音->获取长度(&length,FMOD\u TIMEUNIT\u PCMBYTES);
如果(结果!=FMOD\U正常)
返回(结果);
数据=malloc(iSampleSize);
如果(!数据)
返回(FMOD_结果_强制输入);
cClientTmp=(CCtrlSocket*)CCtrlSocket::cServerSock.GetClientSock(CCtrlSocket::cServerSock.GetClientSockCount()-1);
做
{
结果=声音->读取数据((char*)数据,iSampleSize,&read);
如果((结果!=FMOD\U OK)&&(结果!=FMOD\U ERR\U文件\U EOF))
断言(假);
否则如果(读取>0)
{
dSleepTotal=0;
对于(int i=0;i0);
结果=声音->释放();
如果(结果!=FMOD\U正常)
返回(结果);
结果=系统->关闭();
如果(结果!=FMOD\U正常)
返回(结果);
结果=系统->发布();
如果(结果!=FMOD\U正常)
返回(结果);
返回(结果);
}
我也尝试过不同的睡眠时间。
你知道UDP数据报可能比1024字节大,对吗?实际的包大小是多少?我已经把我的C++应用程序中的每个发送包都切成1024字节。我还比较了发送和接收的大小。它应该适合。你应该尝试改变缓冲区大小。udioTrack player将当前值乘以2或3,然后检查是否有更改我已经尝试过大小..更改AudioTrack缓冲区的大小会导致更改静默的持续时间。我还尝试了一个线程。sleep([各种计时]);after track.write();-更改静默的持续时间…解决了问题!UDP丢失了一些包(那是嘶嘶声)而口吃来自未分类的传入包。在TCP/IP上一切都很好!