rtp/rtcp stack

custom rtp

ORTP

UCL Common RTP library

Bell Labs RTP Library

jrtplib

1、custom rtp send/recv

send.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <netinet/in.h>
  6. #include <sys/socket.h>
  7. #include <arpa/inet.h>
  8.  
  9. #define TS_PACKET_SIZE 188
  10. #define MTU 1500
  11.  
  12. /*rtp struct*/
  13. struct rtp_header{
  14. uint16_t cc:4;
  15. uint16_t x:1;
  16. uint16_t p:1;
  17. uint16_t v:2;
  18. uint16_t pt:7;
  19. uint16_t m:1;
  20. uint16_t sequence_number;
  21. uint32_t timestamp;
  22. uint32_t ssrc;
  23. };
  24.  
  25. void init_rtp_header(struct rtp_header *h){
  26. h->v = 2;
  27. h->p = 0;
  28. h->x = 0;
  29. h->cc = 0;
  30. h->m = 0;
  31. h->pt = 8;
  32. h->sequence_number =0;
  33. h->timestamp = 0;
  34. h->ssrc =0;
  35. }
  36.  
  37. void sequence_number_increase(struct rtp_header *header, uint32_t timestamp){
  38. uint16_t sequence = ntohs(header->sequence_number);
  39. sequence++;
  40. header->sequence_number = htons(sequence);
  41. uint32_t user_ts = ntohl(header->timestamp);
  42. user_ts += timestamp;
  43. header->timestamp = htonl(user_ts);
  44. }
  45.  
  46. int main(int argc,char *argv[]){
  47. char buf[MTU];
  48. unsigned int count = 0;
  49. if(argc < 2){
  50. printf(" need wav path \n");
  51. return -1;
  52. }
  53.  
  54. init_rtp_header((struct rtp_header*)buf);
  55. count = sizeof(struct rtp_header);
  56.  
  57. int sock = socket(AF_INET, SOCK_DGRAM, 0);
  58. struct sockaddr_in dest_addr;
  59.  
  60. dest_addr.sin_family=AF_INET;
  61. dest_addr.sin_port = htons(10001);
  62. dest_addr.sin_addr.s_addr =inet_addr("127.0.0.1");
  63.  
  64. bzero(&(dest_addr.sin_zero),8);
  65.  
  66. // Open TS file
  67. FILE *ts_file = fopen(argv[1], "r+");
  68. int n=0;
  69. while(!feof(ts_file)){
  70. int read_len = fread(buf+count, 1, TS_PACKET_SIZE, ts_file);
  71. count += read_len;
  72. if (count + TS_PACKET_SIZE > MTU){
  73. printf("haha_count = %d\n",count);
  74. sequence_number_increase((struct rtp_header*)buf, 160);
  75. sendto(sock, buf, count, 0, (const struct sockaddr*)&dest_addr, sizeof(dest_addr));
  76. count = sizeof(struct rtp_header);
  77. usleep(10000);
  78. n++;
  79. }
  80. }
  81. printf("numofcount:%d\n",n*1316);
  82.  
  83. fclose(ts_file);
  84. }

recv.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/stat.h>
  6. #include <sys/types.h>
  7. #include <dirent.h>
  8. #include <sys/file.h>
  9. #include <errno.h>
  10. #include <netdb.h>
  11. #include <netinet/in.h>
  12. #include <arpa/inet.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/time.h>
  15. #include <string.h>
  16. #include <stdarg.h>
  17. #include <sys/ipc.h>
  18. #include <sys/sem.h>
  19. #include <signal.h>
  20. #include <sys/wait.h>
  21. #include <regex.h>
  22.  
  23. /*rtp struct*/
  24. struct rtp_header{
  25. uint16_t cc:4;
  26. uint16_t x:1;
  27. uint16_t p:1;
  28. uint16_t v:2;
  29. uint16_t pt:7;
  30. uint16_t m:1;
  31. uint16_t sequence_number;
  32. uint32_t timestamp;
  33. uint32_t ssrc;
  34. };
  35.  
  36. void main(int argc, char **argv)
  37. {
  38. int socka;
  39. int nPortA = 10001;
  40. fd_set rfd;
  41. struct timeval timeout;
  42. struct sockaddr_in addr;
  43. char recv_buf[1500];
  44.  
  45. int nRecLen;
  46.  
  47. struct sockaddr_in cli;
  48. int nRet;
  49.  
  50. socka = socket(AF_INET, SOCK_DGRAM, 0);
  51. if (socka == -1)
  52. {
  53. printf("socket()/n");
  54. return;
  55. }
  56.  
  57. memset(&addr, 0, sizeof(addr));
  58.  
  59. addr.sin_family = AF_INET;
  60. addr.sin_port = htons(nPortA);
  61. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  62. if (bind(socka, (struct sockaddr*)&addr, sizeof(addr)) == -1)
  63. {
  64. printf("bind()/n");
  65. return;
  66. }
  67.  
  68. //timeout = 6s
  69. timeout.tv_sec = 6;
  70. timeout.tv_usec = 0;
  71.  
  72. memset(recv_buf, 0, sizeof(recv_buf));
  73.  
  74. FILE *fp_write = fopen("out.ps", "wb+");
  75.  
  76. while (1)
  77. {
  78. FD_ZERO(&rfd);
  79.  
  80. FD_SET(socka, &rfd);
  81.  
  82. nRet = select(socka+1, &rfd, NULL, NULL, &timeout);
  83. if (nRet == -1)
  84. {
  85. printf("select()\n");
  86. return;
  87. }
  88. else if (nRet == 0)
  89. {
  90. //printf("timeout\n");
  91. continue;
  92. }
  93. else
  94. {
  95. if (FD_ISSET(socka, &rfd))
  96. {
  97. nRecLen = sizeof(cli);
  98. int nRecEcho = recvfrom(socka, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&cli, &nRecLen);
  99. if (nRecEcho == -1)
  100. {
  101. printf("recvfrom()\n");
  102. break;
  103. }
  104.  
  105. struct rtp_header *p = (struct rtp_header *)recv_buf;
  106. printf("v = %d\n",p->v);
  107. printf("p = %d\n",p->p);
  108. printf("x = %d\n",p->x);
  109. printf("cc = %d\n",p->cc);
  110. printf("m = %d\n",p->m);
  111. printf("pt = %d\n",p->pt);
  112. printf("sequence_number = %d\n",ntohs(p->sequence_number));
  113. printf("timestamp = %d\n",ntohl(p->timestamp));
  114. printf("ssrc = %d\n",ntohl(p->ssrc));
  115.  
  116. if (!feof(fp_write)) {
  117. fwrite(recv_buf, 1, nRecEcho, fp_write);
  118. }
  119. }
  120.  
  121. }
  122. }
  123. }

gcc -o send send.c -lm
gcc -o recv recv.c -lm

./recv

./send fileSequence0.ts

test file

https://www.cnblogs.com/dong1/p/10451577.html

2、jrtplib

1) 安装库文件

_install.sh

  1. cmake -DCMAKE_INSTALL_PREFIX=./_install
  2. make
  3. make install

2)编译example

_build.sh

  1. export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
  2.  
  3. rm ./test
  4.  
  5. g++ example1.cpp -I./_install/include/jrtplib3 -L./_install/lib -g -o test -ljrtp

3)测试example

dong@ubuntu:~/sip/jrtplib/example$ ls
_build.sh  example1.cpp  _install  test
dong@ubuntu:~/sip/jrtplib/example$ ./test
Using version 3.11.1
Enter local portbase:
4000

Enter the destination IP address
127.0.0.1
Enter the destination port
4000

Number of packets you wish to be sent:
10

Sending packet 1/10

Sending packet 2/10
Got packet !

Sending packet 3/10
Got packet !

Sending packet 4/10
Got packet !

Sending packet 5/10
Got packet !

Sending packet 6/10
Got packet !

Sending packet 7/10
Got packet !

Sending packet 8/10
Got packet !

Sending packet 9/10
Got packet !

Sending packet 10/10
Got packet !
dong@ubuntu:~/sip/jrtplib/example$

4)jrtplib的rtp大小端问题

1)README.md里有一句话

- `RTP_BIG_ENDIAN`: If set, assume big-endian byte ordering.

2)CMakeLists.txt里有一段代码

if (CMAKE_CROSSCOMPILING)
    option (JRTPLIB_USE_BIGENDIAN "Target platform is big endian" ON)
    if (JRTPLIB_USE_BIGENDIAN)
        set(RTP_ENDIAN "#define RTP_BIG_ENDIAN")
    else (JRTPLIB_USE_BIGENDIAN)
        set(RTP_ENDIAN "// Little endian system")
    endif (JRTPLIB_USE_BIGENDIAN)
else (CMAKE_CROSSCOMPILING)
    test_big_endian(JRTPLIB_BIGENDIAN)
    if (JRTPLIB_BIGENDIAN)
        set(RTP_ENDIAN "#define RTP_BIG_ENDIAN")
    else (JRTPLIB_BIGENDIAN)
        set(RTP_ENDIAN "// Little endian system")
    endif (JRTPLIB_BIGENDIAN)
endif (CMAKE_CROSSCOMPILING)

3)从以上信息可以确认默认是大端模式

注释掉jrtplib-3.11.1/src/rtpconfig.h.in的56行就是小端模式

//${RTP_ENDIAN}

4) ERR_RTP_SESSION_CANTGETLOGINNAME

因为login不能创建会话,注释掉

  1. // if (!gotlogin)
  2. // {
  3. // char *logname = getenv("LOGNAME");
  4. // if (logname == 0)
  5. // return ERR_RTP_SESSION_CANTGETLOGINNAME;
  6. // strncpy((char *)buffer,logname,*bufferlength);
  7. // }
  8. if (!gotlogin)
  9.  
  10. {
  11.  
  12. char *logname = getenv( "LOGNAME" );
  13.  
  14. if( == logname )
  15.  
  16. {
  17.  
  18. printf( "Can't getenv LOGNAME, we will use \"root\" instead\n" );
  19.  
  20. strncpy( ( char * )buffer, "root", *bufferlength );
  21.  
  22. }
  23.  
  24. else
  25.  
  26. {
  27.  
  28. strncpy( ( char * )buffer, logname, *bufferlength );
  29.  
  30. }
  31.  
  32. }

5)实际应用

将jrtplib-3.11.1/examples/example1.cpp拆分成发送和接收

send.cpp

  1. /*
  2. Here's a small IPv4 example: it asks for a portbase and a destination and
  3. starts sending packets to that destination.
  4. */
  5.  
  6. #include "rtpsession.h"
  7. #include "rtpudpv4transmitter.h"
  8. #include "rtpipv4address.h"
  9. #include "rtpsessionparams.h"
  10. #include "rtperrors.h"
  11. #include "rtplibraryversion.h"
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <iostream>
  15. #include <string>
  16.  
  17. using namespace jrtplib;
  18.  
  19. void checkerror(int rtperr)
  20. {
  21. if (rtperr < 0)
  22. {
  23. std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
  24. exit(-1);
  25. }
  26. }
  27.  
  28. int main(void)
  29. {
  30.  
  31. RTPSession sess;
  32. uint16_t portbase = 3000;
  33. uint16_t destport = 4000;
  34. uint32_t destip;
  35.  
  36. int status,i;
  37. int num = 10;
  38.  
  39. destip = inet_addr("127.0.0.1");
  40. if (destip == INADDR_NONE)
  41. {
  42. std::cerr << "Bad IP address specified" << std::endl;
  43. return -1;
  44. }
  45.  
  46. destip = ntohl(destip);
  47.  
  48. RTPUDPv4TransmissionParams transparams;
  49. RTPSessionParams sessparams;
  50.  
  51. sessparams.SetOwnTimestampUnit(1.0/10.0);
  52. sessparams.SetAcceptOwnPackets(true);
  53.  
  54. transparams.SetPortbase(portbase);
  55.  
  56. status = sess.Create(sessparams,&transparams);
  57. checkerror(status);
  58.  
  59. RTPIPv4Address addr(destip,destport);
  60. status = sess.AddDestination(addr);
  61. checkerror(status);
  62.  
  63. for (i = 1 ; i <= num ; i++)
  64. {
  65. printf("\nSending packet %d/%d\n",i,num);
  66.  
  67. // send the packet
  68. status = sess.SendPacket((void *)"1234567890",10,0,false,10);
  69. checkerror(status);
  70.  
  71. RTPTime::Wait(RTPTime(1,0));
  72. }
  73.  
  74. sess.BYEDestroy(RTPTime(10,0),0,0);
  75.  
  76. return 0;
  77. }

recv.cpp

  1. /*
  2. Here's a small IPv4 example: it asks for a portbase and a destination and
  3. starts sending packets to that destination.
  4. */
  5.  
  6. #include "rtpsession.h"
  7. #include "rtpudpv4transmitter.h"
  8. #include "rtpipv4address.h"
  9. #include "rtpsessionparams.h"
  10. #include "rtperrors.h"
  11. #include "rtplibraryversion.h"
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <iostream>
  15. #include <string>
  16.  
  17. using namespace jrtplib;
  18.  
  19. void checkerror(int rtperr)
  20. {
  21. if (rtperr < 0)
  22. {
  23. std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
  24. exit(-1);
  25. }
  26. }
  27.  
  28. int main(void)
  29. {
  30. RTPSession sess;
  31. uint16_t portbase = 4000;
  32.  
  33. int status;
  34.  
  35. RTPUDPv4TransmissionParams transparams;
  36. RTPSessionParams sessparams;
  37.  
  38. sessparams.SetOwnTimestampUnit(1.0/10.0);
  39. sessparams.SetAcceptOwnPackets(true);
  40.  
  41. transparams.SetPortbase(portbase);
  42.  
  43. status = sess.Create(sessparams,&transparams);
  44. checkerror(status);
  45.  
  46. while(1)
  47. {
  48.  
  49. sess.BeginDataAccess();
  50.  
  51. // check incoming packets
  52. if (sess.GotoFirstSourceWithData())
  53. {
  54. do
  55. {
  56. RTPPacket *pack;
  57.  
  58. while ((pack = sess.GetNextPacket()) != NULL)
  59. {
  60. // You can examine the data here
  61. printf("Got packet !\n");
  62.  
  63. // we don't longer need the packet, so
  64. // we'll delete it
  65. sess.DeletePacket(pack);
  66. }
  67. } while (sess.GotoNextSourceWithData());
  68. }
  69.  
  70. sess.EndDataAccess();
  71.  
  72. #ifndef RTP_SUPPORT_THREAD
  73. status = sess.Poll();
  74. checkerror(status);
  75. #endif // RTP_SUPPORT_THREAD
  76.  
  77. }
  78.  
  79. sess.BYEDestroy(RTPTime(10,0),0,0);
  80.  
  81. return 0;
  82. }

_build.sh

  1. export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
  2.  
  3. rm ./send ./recv
  4.  
  5. g++ send.cpp -I./_install/include/jrtplib3 -L./_install/lib -g -o send -ljrtp
  6. g++ recv.cpp -I./_install/include/jrtplib3 -L./_install/lib -g -o recv -ljrtp

3、ortp是个坑

1) 安装库文件

_install.sh

  1. #https://blog.csdn.net/yanchenyu365/article/details/78724790
  2. #再经过阅读26.0版本日志发现,只是27.0有了那么多依赖,增加的功能对Linux又没啥意义,
  3. #26.0 及其以前版本,直接就可以安装!直接就可以安装!直接就可以安装
  4.  
  5. rm -rf /home/dong/_install
  6. ./autogen.sh
  7. ./configure --prefix=/home/dong/_install --enable-static --enable-shared
  8. make && make install

2)Example

ortp-0.26.0/src/tests/rtpsend.c

ortp-0.26.0/src/tests/rtprecv.c

_build.sh

  1. export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
  2.  
  3. rm ./send ./recv
  4.  
  5. gcc -g -o send rtpsend.c -I./_install/include -L./_install/lib -lortp
  6. gcc -g -o recv rtprecv.c -I./_install/include -L./_install/lib -lortp

3)Debug

rtpsend.c

  1. ortp_init();
  2. //ortp_scheduler_init();
  3. ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
  4. session=rtp_session_new(RTP_SESSION_SENDONLY);
  5.  
  6. //rtp_session_set_scheduling_mode(session,1);
  7. //rtp_session_set_blocking_mode(session,1);
  8. //rtp_session_set_connected_mode(session,TRUE);
  9. rtp_session_set_remote_addr(session,argv[2],atoi(argv[3]));
  10. rtp_session_set_payload_type(session,8);

rtprecv.c

  1. ortp_init();
  2. //ortp_scheduler_init();
  3. ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
  4. signal(SIGINT,stop_handler);
  5. session=rtp_session_new(RTP_SESSION_RECVONLY);
  6. //rtp_session_set_scheduling_mode(session,1);
  7. //rtp_session_set_blocking_mode(session,1);
  8. rtp_session_set_local_addr(session,"0.0.0.0",atoi(argv[2]),-1);
  9. //rtp_session_set_connected_mode(session,TRUE);
  10. //rtp_session_set_symmetric_rtp(session,TRUE);
  11. //rtp_session_enable_adaptive_jitter_compensation(session,adapt);
  12. //rtp_session_set_jitter_compensation(session,jittcomp);
  13. rtp_session_set_payload_type(session,8);
  14. //rtp_session_signal_connect(session,"ssrc_changed",(RtpCallback)ssrc_cb,0);
  15. //rtp_session_signal_connect(session,"ssrc_changed",(RtpCallback)rtp_session_reset,0);

./send file.g711a 127.0.0.1 4000

./recv test 4000

遗留bug

rtpsend能正常发送,rtprecv接收有问题,如果你解决了,记得告诉我,感谢!

dong@ubuntu:~/sip/ortp/example$ gdb recv
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from recv...done.
(gdb) set args test 4000
(gdb) r
Starting program: /home/dong/sip/ortp/example/recv test 4000
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
2019-12-05 18:20:15:555 ortp-message-RtpSession bound to [0.0.0.0] ports [4000] [38524]

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bccbf3 in concatb (mp=mp@entry=0x6043c0, newm=newm@entry=0x0)
    at str_utils.c:317
317        while(newm->b_cont!=NULL) newm=newm->b_cont;
(gdb)

闲散下来再来修复...

靠,ortp官网处处都是陷阱

http://www.linphone.org/index.php/eng/code_review/ortp/

https://gitlab.linphone.org/BC/public/ortp

ortp的分支有些特性不同,下载源码需要注意

a) 数据收发demo在src/tests/目录

src/tests/rtpsend.c

src/tests/rtprecv.c

b) rtp数据流的处理以及质量反馈

rtcp feedback模块

rtcp_fb.c

rtcp扩展模块

rtcp_xf.c

4、Bell Labs

RTP Library

http://www.cs.columbia.edu/irt/software/rtplib/

5、UCL Common Code Library

伦敦大学学院的通用代码库里的rtp/rtcp部分

University College London

rtpdemo.c

  1. /*
  2. * rtpdemo: A simple rtp application that sends and receives data.
  3. *
  4. * (C) 2000-2001 University College London.
  5. */
  6.  
  7. #include <sys/time.h>
  8.  
  9. #include <ctype.h>
  10. #include <inttypes.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15.  
  16. #include "uclconf.h"
  17. #include "config_unix.h"
  18. #include "config_win32.h"
  19. #include "debug.h"
  20. #include "memory.h"
  21. #include "rtp.h"
  22.  
  23. static void
  24. usage()
  25. {
  26. printf("Usage: rtpdemo [switches] address port\n");
  27. printf("Valid switches are:\n");
  28. printf(" -f\t\tFilter local packets out of receive stream.\n");
  29. printf(" -l\t\tListen and do not transmit data.\n");
  30. exit(-1);
  31. }
  32.  
  33. /* ------------------------------------------------------------------------- */
  34. /* RTP callback related */
  35.  
  36. static void
  37. sdes_print(struct rtp *session, uint32_t ssrc, rtcp_sdes_type stype) {
  38. const char *sdes_type_names[] = {
  39. "end", "cname", "name", "email", "telephone",
  40. "location", "tool", "note", "priv"
  41. };
  42. const uint8_t n = sizeof(sdes_type_names) / sizeof(sdes_type_names[0]);
  43.  
  44. if (stype > n) {
  45. /* Theoretically impossible */
  46. printf("boo! invalud sdes field %d\n", stype);
  47. return;
  48. }
  49.  
  50. printf("SSRC 0x%08x reported SDES type %s - ", ssrc,
  51. sdes_type_names[stype]);
  52.  
  53. if (stype == RTCP_SDES_PRIV) {
  54. /* Requires extra-handling, not important for example */
  55. printf("don't know how to display.\n");
  56. } else {
  57. printf("%s\n", rtp_get_sdes(session, ssrc, stype));
  58. }
  59. }
  60.  
  61. static void
  62. packet_print(struct rtp *session, rtp_packet *p)
  63. {
  64. printf("Received data (payload %d timestamp %06d size %d) ", p->pt, p->ts, p->data_len);
  65.  
  66. if (p->ssrc == rtp_my_ssrc(session)) {
  67. /* Unless filtering is enabled we are likely to see
  68. out packets if sending to a multicast group. */
  69. printf("that I just sent.\n");
  70. } else {
  71. printf("from SSRC 0x%08x\n", p->ssrc);
  72. }
  73. }
  74.  
  75. static void
  76. rtp_event_handler(struct rtp *session, rtp_event *e)
  77. {
  78. rtp_packet *p;
  79. rtcp_sdes_item *r;
  80.  
  81. switch(e->type) {
  82. case RX_RTP:
  83. p = (rtp_packet*)e->data;
  84. packet_print(session, p);
  85. xfree(p); /* xfree() is mandatory to release RTP packet data */
  86. break;
  87. case RX_SDES:
  88. r = (rtcp_sdes_item*)e->data;
  89. sdes_print(session, e->ssrc, r->type);
  90. break;
  91. case RX_BYE:
  92. break;
  93. case SOURCE_CREATED:
  94. printf("New source created, SSRC = 0x%08x\n", e->ssrc);
  95. break;
  96. case SOURCE_DELETED:
  97. printf("Source deleted, SSRC = 0x%08x\n", e->ssrc);
  98. break;
  99. case RX_SR:
  100. case RX_RR:
  101. case RX_RR_EMPTY:
  102. case RX_RTCP_START:
  103. case RX_RTCP_FINISH:
  104. case RR_TIMEOUT:
  105. case RX_APP:
  106. break;
  107. }
  108. fflush(stdout);
  109. }
  110.  
  111. /* ------------------------------------------------------------------------- */
  112. /* Send and receive loop. Sender use 20ms audio mulaw packets */
  113.  
  114. #define MULAW_BYTES 4 * 160
  115. #define MULAW_PAYLOAD 0
  116. #define MULAW_MS 4 * 20
  117.  
  118. #define MAX_ROUNDS 100
  119.  
  120. static void
  121. rxtx_loop(struct rtp* session, int send_enable)
  122. {
  123. struct timeval timeout;
  124. uint32_t rtp_ts, round;
  125. uint8_t mulaw_buffer[MULAW_BYTES];
  126.  
  127. if (send_enable) {
  128. printf("Sending and listening to ");
  129. } else {
  130. printf("Listening to ");
  131. }
  132. printf("%s port %d (local SSRC = 0x%08x)\n",
  133. rtp_get_addr(session),
  134. rtp_get_rx_port(session),
  135. rtp_my_ssrc(session));
  136.  
  137. round = 0;
  138.  
  139. for(round = 0; round < MAX_ROUNDS; round++) {
  140. rtp_ts = round * MULAW_MS;
  141.  
  142. /* Send control packets */
  143. rtp_send_ctrl(session, rtp_ts, NULL);
  144.  
  145. /* Send data packets */
  146. if (send_enable) {
  147. rtp_send_data(session, rtp_ts, MULAW_PAYLOAD,
  148. 0, 0, 0,
  149. (char*)mulaw_buffer, MULAW_BYTES,
  150. 0, 0, 0);
  151. }
  152.  
  153. /* Receive control and data packets */
  154. timeout.tv_sec = 0;
  155. timeout.tv_usec = 0;
  156. rtp_recv(session, &timeout, rtp_ts);
  157.  
  158. /* State maintenance */
  159. rtp_update(session);
  160.  
  161. usleep(MULAW_MS * 1000);
  162. xmemchk();
  163. }
  164. }
  165.  
  166. /* ------------------------------------------------------------------------- */
  167. /* Main loop: parses command line and initializes RTP session */
  168.  
  169. int
  170. main(int argc, const char *argv[])
  171. {
  172. const char *address = NULL;
  173. struct rtp *session = NULL;
  174. uint16_t port = 0;
  175. int32_t ac, filter_me = 0, send_enable = 1;
  176.  
  177. ac = 1;
  178. while (ac < argc && argv[ac][0] == '-') {
  179. switch(tolower(argv[ac][1])) {
  180. case 'f':
  181. filter_me = 1;
  182. break;
  183. case 'l':
  184. send_enable = 0;
  185. break;
  186. }
  187. ac++;
  188. }
  189.  
  190. if (argc - ac != 2) {
  191. usage();
  192. }
  193.  
  194. address = argv[ac];
  195. port = atoi(argv[ac + 1]);
  196.  
  197. session = rtp_init(address, /* Host/Group IP address */
  198. port, /* receive port */
  199. port, /* transmit port */
  200. 16, /* time-to-live */
  201. 64000, /* B/W estimate */
  202. rtp_event_handler, /* RTP event callback */
  203. NULL); /* App. specific data */
  204.  
  205. if (session) {
  206. const char *username = "Malcovich Malcovitch";
  207. const char *telephone = "1-800-RTP-DEMO";
  208. const char *toolname = "RTPdemo";
  209.  
  210. uint32_t my_ssrc = rtp_my_ssrc(session);
  211.  
  212. /* Set local participant info */
  213. rtp_set_sdes(session, my_ssrc, RTCP_SDES_NAME,
  214. username, strlen(username));
  215. rtp_set_sdes(session, my_ssrc, RTCP_SDES_PHONE,
  216. telephone, strlen(telephone));
  217. rtp_set_sdes(session, my_ssrc, RTCP_SDES_TOOL,
  218. toolname, strlen(toolname));
  219.  
  220. /* Filter out local packets if requested */
  221. rtp_set_option(session, RTP_OPT_FILTER_MY_PACKETS, filter_me);
  222.  
  223. /* Run main loop */
  224. rxtx_loop(session, send_enable);
  225.  
  226. /* Say bye-bye */
  227. rtp_send_bye(session);
  228. rtp_done(session);
  229. } else {
  230. printf("Could not initialize session for %s port %d\n",
  231. address,
  232. port);
  233. }
  234.  
  235. return 0;
  236. }

https://files.cnblogs.com/files/dong1/common-1.2.14.tar.gz

rtp/rtcp的更多相关文章

  1. TCP、UDP、RTP(RTCP)异同与区别

    OSI七层模型OSI 中的层            功能                                                        TCP/IP协议族 应 用层   ...

  2. Android IOS WebRTC 音视频开发总结(八十六)-- WebRTC中RTP/RTCP协议实现分析

    本文主要介绍WebRTC中的RTP/RTCP协议,作者:weizhenwei ,文章最早发表在编风网,微信ID:befoio 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID ...

  3. 流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls)

    RTP           参考文档 RFC3550/RFC3551 Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传输层协议.RTP协议详细 ...

  4. RTP RTCP在音视频传输与同步方面的使用

    转自:http://blog.csdn.net/kof98765/article/details/17733701 1 音视频实时传输 1.1 Jrtplib库介绍 本系统采用开源库Jrtplib进行 ...

  5. RTP/RTCP/RTSP/SIP/SDP 关系(直接看总结)

    RTP/RTCP/RTSP/SIP/SDP 关系   RTP(实时传输协议,传输层) Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传输层协议 ...

  6. [转]流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls)

    [转]流媒体协议介绍(rtp/rtcp/rtsp/rtmp/mms/hls) http://blog.csdn.net/tttyd/article/details/12032357 RTP       ...

  7. 了解实时媒体的播放(RTP/RTCP 和 RTSP)

    http://blog.csdn.net/span76/article/details/12913307 RTP/RTCP RTP是基于 UDP协议的, UDP不用建立连接,效率更高:但允许丢包, 这 ...

  8. SIP SDP RTSP RTP RTCP webrtc

    rfc1889  rfc2326  rfc3261  rfc3550  rfc3856  rfc6120. SIP SDP RTSP  RTP RTCP,就像他们出现的顺序一样,他们在实际应用中的启用 ...

  9. RTP, RTCP, RTSP 协议介绍

    流媒体是边下载边播放的方式, 是视频会议.IP电话等应用场合的技术基础.           为什么TCP/IP协议就不能满足多媒体通信的要求呢?因为TCP有以下4个特点:1.TCP重传机制2.TCP ...

  10. 【转】TCP、UDP、RTP(RTCP)区别

    转自:https://www.cnblogs.com/imystr/p/4026639.html OSI七层模型OSI 中的层            功能                        ...

随机推荐

  1. java selenium常用API汇总

    (WebElement.iFrame.select.alert.浏览器窗口.事件.js)     一 WebElement相关方法 1.点击操作 WebElement button = driver. ...

  2. bzoj5118 Fib数列2 二次剩余+矩阵快速幂

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5118 题解 这个题一看就是不可做的样子. 求斐波那契数列的第 \(n\) 项,\(n \leq ...

  3. 前端每日实战:86# 视频演示如何用纯 CSS 创作一个方块旋转动画

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/gjgyWm 可交互视频 此视频是可 ...

  4. MongoDB Compass管理工具下载、安装和使用

    内容来自:https://jingyan.baidu.com/article/925f8cb884f6f8c0dce0565a.html ,https://blog.csdn.net/bg101775 ...

  5. 16 :IDEA快速键

    ctrol+z ctrol+shift+z  重做 复制,粘贴,删除,(行操作,光标放在那里就可以操作,不要全选择) 注:特别:查询出来,文件是可以直接编辑的 crtol+F double +shif ...

  6. nodejs廖雪峰大神教程

    https://www.liaoxuefeng.com/wiki/1022910821149312/1023025235359040

  7. Guid--调用Guid.genID();

    package com.ufgov.ar.common.util; import java.net.InetAddress; /** * <p> * Title: 产生唯一标识 /** * ...

  8. BUUCTF | [CISCN2019 华北赛区 Day1 Web1]Dropbox

    步骤: 1.运行这个: <?php class User { public $db; } class File { public $filename; } class FileList { pr ...

  9. promise以及async、await学习总结

    Promise/async.await帮我们解决了什么 它给我们提供了一种新的异步编程解决方案,同时避免了困扰已久的回调地狱 // 异步的处理可能会产生这样的回调地狱(第二个异步操作和第一个异步的结果 ...

  10. EZOJ #361地理

    分析 就是分别维护l和r的个数 然后对于询问区间[L,R] 之后l树状数组中小于等于R的个数减掉r树状数组中小于L的即可 代码 #include<bits/stdc++.h> using ...