使用eXsip和ORTP通话(一)

#include "stdafx.h"     
#include "YouToo.h"     
#include "YouTooDlg.h"     
     
#define WAIT_TIMER 200                   //事件检测时间间隔ms     
#define REG_TIMER   30*1000           //注册时间间隔ms     
     
bool build_media(int local_port, const char *remote_ip,       
                                 int remote_port, int payload, const char *fmtp, int jitter, bool ec, int bitrate);     
     
CYouTooDlg *dlg_wnd = NULL;     
     
AudioStream *audio = NULL;     
RtpProfile *profile = NULL;     
RtpSession *session = NULL;     
OrtpEvQueue *q = NULL;     

#ifdef _DEBUG     
#define new DEBUG_NEW     
#undef THIS_FILE     
static char THIS_FILE[] = __FILE__;     
#endif     

#define DEBUG_INFO debug_info->AddString     

UINT sip_ua_monitor(void *pArg)     
   
       bool ret = false;     
       char *payload_str;                                        
       char localip[128];     
       char tmp[4096];         

       CString dtmf_str;     
       char dtmf[50] = {0};       

       int reg_remain = REG_TIMER;       

       CYouTooDlg *pMainWnd = (CYouTooDlg *)pArg;     
       CListBox *debug_info = ((CListBox *)pMainWnd->GetDlgItem(IDC_INFO));       

       DEBUG_INFO("Event monitor for ua[c|s] start!");       

       eXosip_event_t *uac_e;                                
       osip_message_t *ack = NULL;                      
       osip_message_t *answer = NULL;                  

            
       sdp_message_t * msg_rsp = NULL;     
       sdp_connection_t * con_rsp = NULL;     
       sdp_media_t * md_rsp = NULL;     
     
            
       sdp_message_t * msg_req = NULL;     
       sdp_connection_t * con_req = NULL;     
       sdp_media_t * md_req = NULL;       

       char out_str[100] = {0};       

       eXosip_lock ();     
       eXosip_automatic_action();     
       eXosip_unlock ();       

       while(pMainWnd->doing)     
       {     
               eXosip_lock ();     
               uac_e = eXosip_event_wait (0, WAIT_TIMER);     
               eXosip_unlock ();       

               reg_remain = reg_remain - WAIT_TIMER;     
               if(reg_remain < 0)     
               {     
                       //超时,重新注册     
                       eXosip_lock ();     
                       eXosip_automatic_refresh();     
                       eXosip_unlock ();     
                       reg_remain = REG_TIMER;     
                       DEBUG_INFO("register timeout,retry!");     
               }     
     
               if(pMainWnd->dtmfing)     
               {                   
                       ((CEdit *)pMainWnd->GetDlgItem(IDC_DTMF_STR))->GetWindowText(dtmf_str);     
                       strcpy(dtmf, dtmf_str.GetBuffer(dtmf_str.GetLength()));       
     
                       for(int index=0; index<50; index++)     
                       {     
                               //依次读取字符     
                               if(dtmf[index] == '\0') break;     
                                     
                                    
                               eXosip_lock();     
                               audio_stream_send_dtmf(audio, dtmf[index]);     
                               eXosip_unlock();     
     
                               sprintf(out_str, "DTMF send <%c> OK!", dtmf[index]);     
                               DEBUG_INFO(out_str);     
                               Sleep(500);     
                       }       

                       pMainWnd->dtmfing = false;     
               }       

               if (uac_e == NULL)     
               {     
                       //DEBUG_INFO("nothing");     
                       continue;     
               }       

               eXosip_lock ();     
               eXosip_default_action(uac_e);          
               eXosip_unlock ();     
     
               if(NULL != uac_e->response)     
               {     
                       //UAC 消息处理前检查     
                       sprintf(out_str, "%d %s", uac_e->response->status_code, uac_e->response->reason_phrase);     
                       DEBUG_INFO(out_str);       
                       if(487 == uac_e->response->status_code)     
                       {     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(取消呼叫成功)");     
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(true);                                   
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(false);     
                               continue;     
                       }       

                       if(480 == uac_e->response->status_code)     
                       {     
                               //480 无应答     
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(true);           
                               pMainWnd->GetDlgItem(IDC_ACCEPT)->EnableWindow(true);       
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(false);                                 
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(无应答)");     
                                     
                               //隐藏接通按钮显示呼叫按钮     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_ACCEPT))->ShowWindow(SW_HIDE);     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_DIAL))->ShowWindow(SW_SHOWNORMAL);     
                                     
                               pMainWnd->picked = false;     
                               pMainWnd->calling = false;     
                               pMainWnd->call_id = 0;     
                               pMainWnd->dialog_id = 0;                               
                               continue;     
                       }     
               }       

               if(NULL != uac_e->request)     
               {     
               }     
     
               if(NULL != uac_e->ack)     
               {     
               }     
                     
               switch (uac_e->type)     
               {     
                       case EXOSIP_CALL_SERVERFAILURE:     
                       case EXOSIP_CALL_RELEASED:     
                                    
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(true);           
                               pMainWnd->GetDlgItem(IDC_ACCEPT)->EnableWindow(true);       
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(false);                                 
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(对方或服务器正忙!)");     
                                     
                               //隐藏接通按钮显示呼叫按钮     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_ACCEPT))->ShowWindow(SW_HIDE);     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_DIAL))->ShowWindow(SW_SHOWNORMAL);     
                                     
                               pMainWnd->call_id = 0;     
                               pMainWnd->dialog_id = 0;     
                               pMainWnd->picked = false;     
                               pMainWnd->calling = false;     
                                     
                               DEBUG_INFO("Dest or Server Busy!");     
                               break;     
     
                            
                       case EXOSIP_CALL_INVITE:     
                               sprintf(out_str, "收到来自 %s 的呼叫!",uac_e->request->from->url->string);     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText(out_str);     
     
                               eXosip_lock ();     
                               eXosip_call_send_answer(uac_e->tid, 180, NULL);     
                               if(0 != eXosip_call_build_answer(uac_e->tid, 200, &answer))     
                               {     
                                       eXosip_call_send_answer(uac_e->tid, 603, NULL);     
                                       AfxMessageBox("error build answer!");     
                                       continue;     
                               }     
                               eXosip_unlock ();     
                                     
                               pMainWnd->call_id = uac_e->cid;                                    //供挂断电话上下文操作     
                               pMainWnd->dialog_id = uac_e->did;     
     
                                    
                               eXosip_guess_localip(AF_INET, localip, 128);     
                               snprintf (tmp, 4096,     
                                       "v=0\r\n"     
                                       "o=youtoo 1 1 IN IP4 %s\r\n"     
                                       "s=##youtoo demo\r\n"     
                                       "c=IN IP4 %s\r\n"     
                                       "t=0 0\r\n"     
                                       "m=audio %d RTP/AVP 0 8 101\r\n"     
                                       "a=rtpmap:0 PCMU/8000\r\n"     
                                       "a=rtpmap:8 PCMA/8000\r\n"     
                                       "a=rtpmap:101 telephone-event/8000\r\n"     
                                       "a=fmtp:101 0-15\r\n", localip, localip, pMainWnd->rtp_port);     
                                     
                               //设置回复的SDP消息体,下一步计划分析消息体     
                               eXosip_lock ();     
                               osip_message_set_body(answer, tmp, strlen(tmp));     
                               osip_message_set_content_type(answer, "application/sdp");     
                                     
                                    
                               msg_req = eXosip_get_remote_sdp(uac_e->did);     
                               con_req = eXosip_get_audio_connection(msg_req);     
                               md_req = eXosip_get_audio_media(msg_req);     
                               eXosip_unlock ();     
                                     
                                    
                                     
                               //隐藏呼叫按钮显示接听按钮     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_ACCEPT))->ShowWindow(SW_SHOWNORMAL);     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_DIAL))->ShowWindow(SW_HIDE);     
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(true);     
     
                               pMainWnd->calling = true;     
     
                               while(!pMainWnd->picked)     
                               {     
                                       //未接通进入循环检测     
                                       Sleep(200);     
                               }     
     
                               eXosip_unlock ();     
                               eXosip_call_send_answer(uac_e->tid, 200, answer);     
                               eXosip_unlock ();     
     
                               DEBUG_INFO("200 ok 发送");     
                               break;     
     
                       case EXOSIP_CALL_CANCELLED:     
                                    
                               //隐藏接通按钮显示呼叫按钮     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_ACCEPT))->ShowWindow(SW_HIDE);     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_DIAL))->ShowWindow(SW_SHOWNORMAL);     
                                     
                               pMainWnd->call_id = 0;     
                               pMainWnd->dialog_id = 0;                               
                               pMainWnd->picked = false;     
                               pMainWnd->calling = false;     
                               pMainWnd->GetDlgItem(IDC_REG_STATUS)->SetWindowText("(已拒绝)");     
                               break;     
     
                       case EXOSIP_CALL_ACK:     
                                    
                               if(pMainWnd->calling)     
                               {     
                                            
                                       ret = build_media(pMainWnd->rtp_port, con_req->c_addr, atoi(md_req->m_port), 0, NULL, 0, 0, 0);     
                                       if(!ret)     
                                       {     
                                               AfxMessageBox("媒体建立失败,无法创建通话,请挂断!");     
                                               //pMainWnd->OnHang();     
                                       }                                   
                               }     
                               break;     
     
                            
                       case EXOSIP_REGISTRATION_SUCCESS:     
                               if(0 < uac_e->response->contacts.nb_elt)          
                               {     
                                       pMainWnd->GetDlgItem(IDC_REG_STATUS)->SetWindowText("(已登录)");     
                                       pMainWnd->GetDlgItem(IDC_REG)->EnableWindow(false);     
                                       pMainWnd->GetDlgItem(IDC_UNREG)->EnableWindow(true);     
     
                                       if(0 == pMainWnd->call_id)     
                                       {     
                                               //第一次手动注册成功时     
                                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(true);     
                                       }     
                               }     
                               else     
                               {     
                                       pMainWnd->GetDlgItem(IDC_REG_STATUS)->SetWindowText("(已注销)");     
                                       pMainWnd->GetDlgItem(IDC_REG)->EnableWindow(true);     
                                       pMainWnd->GetDlgItem(IDC_UNREG)->EnableWindow(false);     
                                       pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(false);     
                                       pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(false);     
                               }     
                               break;     
     
                       case EXOSIP_CALL_CLOSED:     
                               if(audio)       
                               {     
                                       //被动关闭媒体连接(远端触发)     
                                       eXosip_lock ();     
                                       audio_stream_stop(audio);     
                                             
                                       ortp_ev_queue_destroy(q);     
                                       rtp_profile_destroy(profile);     
                                       eXosip_unlock ();     
     
                                       audio = NULL;     
                                       q = NULL;     
                                       profile = NULL;     
                                       DEBUG_INFO("audio stream stoped!");     
                               }     
     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(对方已挂断)");     
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(true);           
                               pMainWnd->GetDlgItem(IDC_ACCEPT)->EnableWindow(true);       
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(false);                                 
     
                               //隐藏接通按钮显示呼叫按钮     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_ACCEPT))->ShowWindow(SW_HIDE);     
                               ((CButton *)pMainWnd->GetDlgItem(IDC_DIAL))->ShowWindow(SW_SHOWNORMAL);     
                                     
                               pMainWnd->call_id = 0;     
                               pMainWnd->dialog_id = 0;                               
                               pMainWnd->picked = false;     
                               pMainWnd->calling = false;     
                               break;     
                                     
                       case EXOSIP_CALL_PROCEEDING:     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(查找连接中..)");     
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(false);                                 
                               break;     
     
                       case EXOSIP_CALL_RINGING:     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(对方振铃)");     
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(true);                           
                               pMainWnd->call_id = uac_e->cid;     
                               pMainWnd->dialog_id = uac_e->did;     
     
                                    
                               break;     
                                     
                       case EXOSIP_CALL_ANSWERED:     
                               //ring_stop(ring_p);                                     
                               pMainWnd->GetDlgItem(IDC_CALL_STATUS)->SetWindowText("(对方已接听)");     
                               pMainWnd->GetDlgItem(IDC_DIAL)->EnableWindow(false);                                 
                               pMainWnd->GetDlgItem(IDC_HANG)->EnableWindow(true);                   
                                     
                               pMainWnd->call_id = uac_e->cid;     
                               pMainWnd->dialog_id = uac_e->did;     
                                     
                               eXosip_lock ();     
                               eXosip_call_build_ack (uac_e->did, &ack);     
                               eXosip_call_send_ack (uac_e->did, ack);     
     
                                    
                               msg_rsp = eXosip_get_sdp_info(uac_e->response);     
                               con_rsp = eXosip_get_audio_connection(msg_rsp);     
                               md_rsp = eXosip_get_audio_media(msg_rsp);     
     
                                    
                               payload_str = (char *)osip_list_get(&md_rsp->m_payloads, 0);     
                               eXosip_unlock ();     
     
                                    
                               ret = build_media(pMainWnd->rtp_port, con_rsp->c_addr, atoi(md_rsp->m_port), atoi(payload_str), NULL, 0, 0, 0);     
                               if(!ret)     
                               {     
                                       AfxMessageBox("媒体建立失败,无法创建通话,请挂断!");     
                                       //pMainWnd->OnHang();     
                               }     
                               break;     
     
                       default:     
                               break;     
               }     
                     
               eXosip_event_free (uac_e);     
     
                    
               debug_info->SetCurSel(debug_info->GetCount()-1);     
       }     
             
       return 0;     
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
oRTP分析 一:关于oRTP.................................................................................................................................2 二:源代码的构建框架...................................................................................................................2 三:有关时间戳的说明.................东了 结构体外,一个更重要的结构体是 。该结构体即是一个会话 的抽象,与会话相关的各种信息都定义在该结构体上或者能够通过该结构体找到。要使用 逑行娸体数据的传输,需要先创建一个会话,之后所有数据的传输都在会话上完成或 基于会话完成。 结构体的定义如下: Rtpsession ext mask pos inc ssrc candidate inc same ssrc count Iw recv pL cha on pay load tyre changed Telep on network error signa events allocator tp Sessiorlisu lticast ttl multicast loopback data Lng current tev d contribut. ing sources use connect ssrc set 图 可以看到,这是一个非常大的结构体,从侧面说明了要维护的与会话相关的量还是比较多的 关于该结构体的比较详细的说明会在后面给出。 的初始化通过接口 完成,外部获得一个新的 是通过调用接 完成。关」 的其他有关配置和获取信息的操作都叮以在文件 中找到定义 使用进行数据传输时,可以在一个任务上完成多个会话流的接收和发送。这得益 中调度模块的支持。要使用调度模块,应用需要在进行的初始化时对调度进 行初始化,将需要调度管理的会话注册到调度模块中,这样当进行接收和发送操作时,先向 调度询问当前会话是否可以进行发送和接收,如果不能进行收发操作,则处理下一个会话。 这有点类似接口上的操作。调度模块使用的数据结构主要为 ,如下图 所示: Reschedule list all sessions r sessions r max w sessions Wmaⅹ unblock select con thread thread running timer RtpTimer t⊥me state timer inc timer inl t LIe I timer unini t interval 图 保存了所有要处理的会话,的意义类似于,在这里分别代表接收、发送以及 异常 等文件实现了调度模块。 数据在底层实际的接收和发送是通过接凵完成的,这些实现在 文 件中 为了方便将移植到不同平台上,实现了对操作系统接口的封装,包括常用的 仼务的创建及销毁,条件变量及互斥锁,进程间的管道通信机制等。这些在文件中实 现 狳了操作系统相关的接口外,为了便于内部操作,实现了部分数据结构,一个是双 向链表,在文件中;一个是队列,在文件 文件中。链表的实现比较简单, 队列的实现相对较复杂一点。首先,队列数据结构由三部分组成:队列头、消息块以及数据 块,图示如下: g stopper gb g count b prev b next b cont datat datab b rptr reserved db freeIn reserved dh ref Buffer 图 上图中从左到右依次为队列头,消息块和数据块ε队列头指向消息块,消息块之间可以构成 双向链衣,这是队列的基本要素。消息块本身不带,数据是由专门的数据块来保存的, 并被消息块指向。上图是一个初始化后的状态,消息块的读写指针都指向数据块的 的开始位置。数据块的和指针则分别指向 空间的开始地址和结束地址处。向 中写入和读出数据后的状态变化如下图: b pre b next b next b cont b con b datap b rptr db base b rptr db base b wptr db lim b wpt db lim db freen db freef reserve db ref reserved db ref Buffer Buffe 图 除了向队列添加消息块外,上述数据结构设计还支持向个消息块添加新的消息块,这样可 以支持一个消息块保存较人块的数据,如下图所示 b cont b rptr dh base do lim reserv
好的,以下是一个使用alsa库采集音频并使用ortp库打包发送的示例代码,您可以参考: ```c #include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> #include <ortp/ortp.h> // 定义音频参数 #define AUDIO_FORMAT SND_PCM_FORMAT_S16_LE #define AUDIO_CHANNELS 1 #define AUDIO_RATE 44100 #define AUDIO_FRAME_SIZE (AUDIO_CHANNELS * snd_pcm_format_width(AUDIO_FORMAT) / 8) int main(int argc, char *argv[]) { // 初始化ortp库 ortp_init(); // 创建rtp会话 RtpSession *session = rtp_session_new(RTP_SESSION_SENDONLY); if (session == NULL) { fprintf(stderr, "Failed to create rtp session\n"); return -1; } // 设置rtp会话参数 rtp_session_set_scheduling_mode(session, RTP_SCHEDULER_TIME); rtp_session_set_blocking_mode(session, 0); rtp_session_set_payload_type(session, 0); rtp_session_set_tx_timestamp(session, 1); rtp_session_enable_adaptive_jitter_compensation(session, 1); // 解析命令行参数获取目标IP和端口号 if (argc < 3) { fprintf(stderr, "Usage: %s <dest_ip> <dest_port>\n", argv[0]); return -1; } const char *dest_ip = argv[1]; int dest_port = atoi(argv[2]); // 创建rtp传输地址 RtpAddress *addr = rtp_address_new(dest_ip, dest_port, NULL); if (addr == NULL) { fprintf(stderr, "Failed to create rtp address\n"); return -1; } // 打开默认alsa音频设备 snd_pcm_t *handle; if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0) < 0) { fprintf(stderr, "Failed to open audio device\n"); return -1; } // 配置alsa音频设备参数 if (snd_pcm_set_params(handle, AUDIO_FORMAT, SND_PCM_ACCESS_RW_INTERLEAVED, AUDIO_CHANNELS, AUDIO_RATE, 1, 500000) < 0) { fprintf(stderr, "Failed to set audio device parameters\n"); return -1; } // 循环读取音频数据并发送rtp包 char audio_buf[AUDIO_FRAME_SIZE * 1024]; int frame_count = 0; while (1) { // 从alsa设备读取音频数据 int read_count = snd_pcm_readi(handle, audio_buf, 1024); if (read_count < 0) { read_count = snd_pcm_recover(handle, read_count, 0); if (read_count < 0) { fprintf(stderr, "Failed to read audio data\n"); break; } } // 创建rtp包并设置其数据 RtpPacket *packet = rtp_packet_new(AUDIO_FRAME_SIZE * read_count); packet->payloadtype = 0; memcpy(packet->payload, audio_buf, AUDIO_FRAME_SIZE * read_count); packet->timestamp = frame_count * AUDIO_FRAME_SIZE / AUDIO_CHANNELS; packet->marker = 0; // 将rtp包发送到目标地址 if (rtp_session_sendto(session, packet->payload, packet->payload_len, addr) < 0) { fprintf(stderr, "Failed to send rtp packet\n"); rtp_packet_free(packet); break; } // 释放rtp包资源 rtp_packet_free(packet); // 增加音频帧计数 frame_count += read_count; } // 关闭alsa设备 snd_pcm_close(handle); // 释放rtp地址和会话资源 rtp_session_destroy(session); rtp_address_destroy(addr); // 清理ortp库资源 ortp_exit(); return 0; } ``` 请注意,此示例代码仅用于演示目的,实际使用时需要根据您的具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值