没办法!在其他板块没有反应,只好移到这个板块。关于文件的读写和socket操作。

linlan999 2009-01-23 08:53:28
在嵌入式系统上调一个软电话的程序linphonec,操作系统是linux,
1.在linphonec和PC上的SIP终端通信时,没有问题,在进行通话时,声卡的指示灯是闪烁的,不通话时是一直亮着的;
2.linphonec之间通信时,只能说几分钟,之后声卡指示灯熄灭;

读写声卡的线程循环代码为:
while(d->read_started || d->write_started)
{
if (d->pcmfd>=0){
if (d->read_started){
struct timeval timeout;
fd_set read_fds;
audio_buf_info info;
if (rm==NULL) rm=allocb(bsize,0);

timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO( &read_fds );
FD_SET( d->pcmfd, &read_fds );
if( select( d->pcmfd + 1, &read_fds, NULL, NULL, &timeout ) == -1 ) {
}
if (FD_ISSET( d->pcmfd, &read_fds ) && ioctl( d->pcmfd, SNDCTL_DSP_GETISPACE, &info ) != -1)
{
if (info.bytes>=bsize)
{
err=read(d->pcmfd,rm->b_wptr,bsize);
if (err<0){
ms_warning("Fail to read %i bytes from soundcard: %s",
bsize,strerror(errno));
}else{
rm->b_wptr+=err;
ms_mutex_lock(&d->mutex);
putq(&d->rq,rm);
ms_mutex_unlock(&d->mutex);
rm=NULL;
}
}
else
{
timeout.tv_sec = 0;
timeout.tv_usec = 5000;
select(0, 0, NULL, NULL, &timeout );
}
}
else
{
timeout.tv_sec = 0;
timeout.tv_usec = 5000;
select(0, 0, NULL, NULL, &timeout );
}
}else {
int sz = read(d->pcmfd,rtmpbuff,bsize);
if( sz!=bsize) ms_warning("sound device read returned %i !",sz);
}
if (d->write_started){

audio_buf_info info;
if( ms_bufferizer_get_avail(d->bufferizer)>=bsize && ioctl( d->pcmfd, SNDCTL_DSP_GETOSPACE, &info ) == 0 ) {
if( info.fragstotal - info.fragments > 15 ) {
static int c=0;
/* drop the fragment if the buffer starts to fill up */
/* we got too much data: I prefer to empty the incoming buffer */
while (ms_bufferizer_get_avail(d->bufferizer)>bsize*4){
ms_mutex_lock(&d->mutex);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
ms_mutex_unlock(&d->mutex);
c=c+err*4;
ms_warning("drop fragment when buffer gets too much data (%i - discarded:%i)", info.fragstotal - info.fragments, c);
if (err==0)
break;
}

}else {
ms_mutex_lock(&d->mutex);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
ms_mutex_unlock(&d->mutex);
err=write(d->pcmfd,wtmpbuff,bsize);
if (err<0){
fprintf(stdout,"<<<<<<<failed to write :%d ,%s \n",errno,strerror(errno));
ms_warning("Fail to write %i bytes from soundcard: %s",
bsize,strerror(errno));
}
}
}

}else {
int sz;
memset(wtmpbuff,0,bsize);
sz = write(d->pcmfd,wtmpbuff,bsize);
if( sz!=bsize) ms_warning("sound device write returned %i !",sz);
}
}else usleep(20000);
}


其中d->pcmfd是声卡的文件描述符;

在linphonec之间进行通话时,write()调用出错,errno,strerror(errno) 信息为 32 ,Broken pipe

更奇怪的是,如果将调用发送语音数据函数的线程中的发送函数(就是sendmsg())注释掉,这种情况下编译生成的程序乙,自然不能发出数据了,但一直能听到对方的声音,并且没有出现write()错误;

#ifdef USE_SENDMSG 
#define MAX_IOV 5 //30 CHANGED BY JIM
static int rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_len){
int error;
struct msghdr msg;
struct iovec iov[MAX_IOV];
int iovlen;
for(iovlen=0; iovlen<MAX_IOV && m!=NULL; m=m->b_cont,iovlen++){
iov[iovlen].iov_base=m->b_rptr;
iov[iovlen].iov_len=m->b_wptr-m->b_rptr;
}
if (iovlen==MAX_IOV){
ortp_error("Too long msgb, didn't fit into iov, end discarded.");
/*ADDED BY JIM*/
fprintf(stdout,"fatal error too long msgb \n");
}
msg.msg_name=(void*)rem_addr;
msg.msg_namelen=addr_len;
msg.msg_iov=&iov[0];
msg.msg_iovlen=iovlen;
msg.msg_control=NULL;
msg.msg_controllen=0;
msg.msg_flags=0;

error=sendmsg(sock,&msg,0);
return error;
}
#endif

不注释掉该函数的程序甲自然就听不到乙方的声音;
这种情况下,两个linphonec都不会出现write()错误。

希望各位给些意见。
谢谢。
...全文
269 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhangcuizhi 2009-12-26
  • 打赏
  • 举报
回复
你好,最近我也在研究linphonec,我把linphonec编译成静态的移植到mini2440开发板上(架构是arm9),出现问题,说下具体的环境:我编译是在 ubuntu下,交叉工具用的是mini2440自带的交叉编译工具链是4.3.2版本。移植以后我用了一台pc和一块板子(mini2440)打电话测试,板子的ip是192.168.1.230,我把pc的设为192.168.1.220,然后板子打给pc能打通能,pc上能听到振铃,pc接起来后显示connected。但是说话就没声音了。反过来,如果是pc打给板子,则能打通,能connect,但是板子不能听到振铃,也不能对话,没声音。不知道能不能给点意见
pennymeng 2009-12-18
  • 打赏
  • 举报
回复
怎么没有继续呢?
linlan999 2009-01-26
  • 打赏
  • 举报
回复
因为寝室没有网络,假期结束再继续。
谢谢大家的关注。
linlan999 2009-01-26
  • 打赏
  • 举报
回复
因为寝室没有网络,假期结束再继续。
谢谢大家的关注。
linzsoft 2009-01-24
  • 打赏
  • 举报
回复
关注帮定,可不可以划出 flowchart 帮助理解?
xiaoyisnail 2009-01-23
  • 打赏
  • 举报
回复
帮顶~
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 arong1234 的回复:]
还有再某些特殊情况下,你似乎写入了bsize个0进去,这种写入是否合法?对方可以正确处理么?
[/Quote]

当电话响铃时,这时线程中只向声卡写write(),不是向对方发送数据。实际上除非测试,否则不会出现向声卡写入0,而且写入0完全没问题,同时也没有声音。

非常感谢arong1234 的关注。
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 arong1234 的回复:]
write失败总得报点什么错误吧?失败的错误码是什么?这种错误码含义是什么?

还有既然注释掉sendmsg就好,那就要问你sendmsg会修改什么影响write的东西了,例如移动了buffer指针,虚构了锁之类的

引用 24 楼 linlan999 的回复:
另外关于socket的问题。
我这么提出来我自己都感觉太奇怪了。
如果我把sendmsg()注释掉,则write()就不会失败了(对方没注释掉,当然可以听到对方的声音了)。
[/Quote]


在linphonec之间进行通话时,write()调用出错,errno,strerror(errno) 信息为 32 ,Broken pipe 。

错误码为32,含义是Broken pipe
sendmsg()这是将发送缓冲区内待发送的数据发送出去,它是一个系统调用,不涉及write()的缓冲区。另外程序中没用到C++。
arong1234 2009-01-23
  • 打赏
  • 举报
回复
还有再某些特殊情况下,你似乎写入了bsize个0进去,这种写入是否合法?对方可以正确处理么?
arong1234 2009-01-23
  • 打赏
  • 举报
回复
write失败总得报点什么错误吧?失败的错误码是什么?这种错误码含义是什么?

还有既然注释掉sendmsg就好,那就要问你sendmsg会修改什么影响write的东西了,例如移动了buffer指针,虚构了锁之类的

[Quote=引用 24 楼 linlan999 的回复:]
另外关于socket的问题。
我这么提出来我自己都感觉太奇怪了。
如果我把sendmsg()注释掉,则write()就不会失败了(对方没注释掉,当然可以听到对方的声音了)。
[/Quote]
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 hhyttppd 的回复:]
问题总是要解决的,楼主记得解决了此问题,在此贴说一下,我到时来学习。
[/Quote]

就是因为这个问题,我都搞了一个月了,希望尽快解决。
太郁闷了...
如果解决了,我一定详细说明。
谢谢大家的回复....
hhyttppd 2009-01-23
  • 打赏
  • 举报
回复
问题总是要解决的,楼主记得解决了此问题,在此贴说一下,我到时来学习。
linlan999 2009-01-23
  • 打赏
  • 举报
回复
另外关于socket的问题。
我这么提出来我自己都感觉太奇怪了。
如果我把sendmsg()注释掉,则write()就不会失败了(对方没注释掉,当然可以听到对方的声音了)。
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 arong1234 的回复:]
所以你得提问是有问题的,你把大家都误导到socket上了
那么pipe如果broken之后,你会怎么做?你有没有记录pipebroken的原因?broken以后你有没有重新打开?
引用 20 楼 linlan999 的回复:
引用 19 楼 arong1234 的回复:
谢谢

我是这么理解的:
灯熄灭说明对声卡的操作有问题,根据打印信息是write()操作失败,信息是BROKEN PIPE;
关于发送和接收,我认为他们都没问题。
[/Quote]

谢谢


在write()失败后,我重新打开了,但问题依旧。
ms_mutex_lock(&write_send_mutex);
err=write(d->pcmfd,wtmpbuff,bsize);
ms_mutex_unlock(&write_send_mutex);

write_time=write_time+1;
if (err<0){
//#ifdef JIMTEST
fprintf(stdout,"<<<<<<<1 err is %d ,d->pcmfd is %d ,bsize is %d \n",err,d->pcmfd,bsize);
fprintf(stdout,"<<<<<<<failed to write :%d ,%s \n",errno,strerror(errno));
//#endif
//when the errno is 32(broken pipe) ,it means that the file represented by fd is closed.
//So I add the following code.But I am not sure about its effect.--JIM
if(d->pcmdev>=0)
close(d->pcmfd);

write_time=write_time-1;
fprintf(stdout,"<<<<<<<<close %d \n",d->pcmfd);
free(rtmpbuff);
free(wtmpbuff);
if (rm!=NULL)
{
freemsg(rm);
rm=NULL;
}
write_error=write_error+1;

goto reopen;
//ms_warning("Fail to write %i bytes from soundcard: %s", bsize,strerror(errno));
}
linlan999 2009-01-23
  • 打赏
  • 举报
回复
再调试时发现,当把读写声卡的线程中

{

audio_buf_info info;
if( ms_bufferizer_get_avail(d->bufferizer)>=bsize && ioctl( d->pcmfd, SNDCTL_DSP_GETOSPACE, &info ) == 0 ) {
if( info.fragstotal - info.fragments > 15 ) {
static int c=0;
/* drop the fragment if the buffer starts to fill up */
/* we got too much data: I prefer to empty the incoming buffer */
while (ms_bufferizer_get_avail(d->bufferizer)>bsize*4){
ms_mutex_lock(&d->mutex);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
ms_mutex_unlock(&d->mutex);
c=c+err*4;
ms_warning("drop fragment when buffer gets too much data (%i - discarded:%i)", info.fragstotal - info.fragments, c);
if (err==0)
break;
}

}else {
ms_mutex_lock(&d->mutex);
err=ms_bufferizer_read(d->bufferizer,wtmpbuff,bsize);
ms_mutex_unlock(&d->mutex);
err=write(d->pcmfd,wtmpbuff,bsize);
if (err<0){
fprintf(stdout,"<<<<<<<failed to write :%d ,%s \n",errno,strerror(errno));
ms_warning("Fail to write %i bytes from soundcard: %s",
bsize,strerror(errno));
}
}
}

}else


运行注释掉后编译出的程序进行通信时(当然此时双方都听不见声音,因为没向声卡写),没有发现问题,由于没有将收到的数据写入声卡,可以看到用于容纳对方语音数据buffer也在逐渐变大。
arong1234 2009-01-23
  • 打赏
  • 举报
回复
所以你得提问是有问题的,你把大家都误导到socket上了
那么pipe如果broken之后,你会怎么做?你有没有记录pipebroken的原因?broken以后你有没有重新打开?
[Quote=引用 20 楼 linlan999 的回复:]
引用 19 楼 arong1234 的回复:
谢谢

我是这么理解的:
灯熄灭说明对声卡的操作有问题,根据打印信息是write()操作失败,信息是BROKEN PIPE;
关于发送和接收,我认为他们都没问题。
[/Quote]
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 arong1234 的回复:]
“思路清晰”也许只有你作为写这个得程序员才这么说,其他人看起来不一定清晰,而且你自己调试时可能也不知道从哪着手

在开始分析之前,问你几个问题
1. 灯灭了意味着什么?是发送失败还是接收失败
不要告诉我都有可能,你得程序必须清晰得告诉你自己是哪边失败了

2. 如果是发送或者接收失败,是因为什么原因失败得


不要以为别人有神仙之眼,很多问题不是从代码上直接可以看出得,你得程序自己需要告诉你一切。
[/Quote]

谢谢

我是这么理解的:
灯熄灭说明对声卡的操作有问题,根据打印信息是write()操作失败,信息是BROKEN PIPE;
关于发送和接收,我认为他们都没问题。
arong1234 2009-01-23
  • 打赏
  • 举报
回复
“思路清晰”也许只有你作为写这个得程序员才这么说,其他人看起来不一定清晰,而且你自己调试时可能也不知道从哪着手

在开始分析之前,问你几个问题
1. 灯灭了意味着什么?是发送失败还是接收失败
不要告诉我都有可能,你得程序必须清晰得告诉你自己是哪边失败了

2. 如果是发送或者接收失败,是因为什么原因失败得


不要以为别人有神仙之眼,很多问题不是从代码上直接可以看出得,你得程序自己需要告诉你一切。
hhyttppd 2009-01-23
  • 打赏
  • 举报
回复
顺藤摸瓜吧,
1 找出可能关闭d->pcmfd的地方(close(d->pcmfd)),为集合U
2 找出可能到达U的C
3 在C取出与sock相关的D

我只知道这么多了。
linlan999 2009-01-23
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 hhyttppd 的回复:]
哦,我看明白了。

你的sock是udp
[/Quote]

是这样的
加载更多回复(16)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧