├── org.jlibrtp ├── .gitignore ├── .settings │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── src │ ├── test │ │ └── java │ │ │ └── org │ │ │ └── jlibrtp │ │ │ ├── validateccrtp │ │ │ ├── package.html │ │ │ ├── CCRTPReceiver.java │ │ │ └── CCRTPSender.java │ │ │ └── test │ │ │ ├── TestRTPSession.java │ │ │ └── protocols │ │ │ └── rtp │ │ │ ├── TestRTPURLMultiSender.java │ │ │ ├── TestRTPURLSender.java │ │ │ └── TestRTPURLReceiver.java │ └── main │ │ └── java │ │ └── org │ │ └── jlibrtp │ │ ├── package.html │ │ ├── README.txt │ │ ├── PktBufNode.java │ │ ├── protocols │ │ └── rtp │ │ │ ├── Handler.java │ │ │ ├── RTPOutputStream.java │ │ │ └── CircularByteBuffer.java │ │ ├── RTPAppIntf.java │ │ ├── DebugAppIntf.java │ │ ├── RTCPAVPFIntf.java │ │ ├── RtcpPktAPP.java │ │ ├── AppCallerThread.java │ │ ├── RtcpPktBYE.java │ │ ├── RTCPAppIntf.java │ │ ├── RtcpPkt.java │ │ ├── RtcpPktRTPFB.java │ │ ├── RtcpPktSR.java │ │ ├── RTPReceiverThread.java │ │ ├── StaticProcs.java │ │ ├── RtcpPktRR.java │ │ ├── CompRtcpPkt.java │ │ ├── DataFrame.java │ │ └── ParticipantDatabase.java ├── .project ├── .classpath └── build.gradle ├── org.jlibrtp.demo ├── .gitignore ├── .settings │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── .classpath ├── .project ├── src │ └── main │ │ └── java │ │ └── org │ │ └── jlibrtp │ │ ├── demo │ │ ├── package.html │ │ ├── UnicastExample.java │ │ ├── SoundReceiverDemo.java │ │ ├── UnicastExample2.java │ │ ├── XmlPacketPlayer.java │ │ └── SoundSenderDemo.java │ │ ├── ValidateParticipantDatabase.java │ │ ├── ValidatePktBuffer.java │ │ ├── ValidateStaticProcs.java │ │ └── ValidateRtcpPkt.java └── build.gradle ├── gradlew ├── settings.gradle ├── .settings └── org.eclipse.buildship.core.prefs ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .gitattributes ├── .project ├── gradle.properties ├── README.md ├── LICENSE └── gradlew.bat /org.jlibrtp/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JVoiceXML/jlibrtp/HEAD/gradlew -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'org.jlibrtp' 2 | include 'org.jlibrtp.demo' 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JVoiceXML/jlibrtp/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /org.jlibrtp/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /.gradle/ 3 | 4 | # Ignore Gradle project-specific cache directory 5 | .gradle 6 | 7 | # Ignore Gradle build output directory 8 | build 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /org.jlibrtp/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.source=1.8 5 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.source=1.8 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /org.jlibrtp/src/test/java/org/jlibrtp/validateccrtp/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

ValidateCcrtp is a small package to test compatibility with ccRTP, a popular C++ 4 | implementation of the RTP protocol. It mimicks demo programs distributed with ccRTP.

5 | 9 | 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | jlibrtp 4 | Project jlibrtp created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /org.jlibrtp/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.jlibrtp 4 | Project org.jlibrtp created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.jlibrtp.demo 4 | Project org.jlibrtp.demo created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /org.jlibrtp/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/demo/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

The jlibrtpDemos package contains simple demonstration programs for testing jlibrtp 4 | and some examples of how the library can be used.

5 |

The programs are distributed as sample code, they are not thought to be particularly 6 | useful by themselves, but the XML tools do give a nice way of looking at your stream in 7 | any web browser. You can also easily edit these files to change the stream. 8 |

9 | 15 | 16 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

The jlibrtp package contains the core classes of jlibrtp. Most of these classes 4 | are protected or private, developers looking to use jlibrtp should only concern 5 | themselves with

6 | 15 |

16 | DebugAppIntf is great for checking network problems and keeping track of packets. 17 | If you need extensive debugging you should statically change the debug values in RTPSession.java 18 | and pay attention to the standard output. 19 |

20 | 21 | 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # 21 | # General settings 22 | # 23 | 24 | name = RTP Library for Java 25 | group = org.jvoicexml 26 | version = 0.2 27 | 28 | JVOICEXML_GROUP = org.jvoicexml 29 | 30 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'signing' 4 | id 'maven-publish' 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | sourceCompatibility = 1.8 12 | targetCompatibility = 1.8 13 | 14 | dependencies { 15 | testImplementation 'junit:junit:4.13.2' 16 | 17 | implementation project(':org.jlibrtp') 18 | implementation 'org.jdom:jdom2:2.0.6' 19 | } 20 | 21 | jar { 22 | manifest { 23 | attributes('Implementation-Title': 'RTP Library for Java Demo', 24 | 'Implementation-Vendor': 'switch', 25 | 'Implementation-Version': version, 26 | 'Built-By' : System.properties['user.name'], 27 | 'Build-Timestamp': new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()), 28 | 'Created-By' : "Gradle ${gradle.gradleVersion}", 29 | 'Build-Jdk' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})", 30 | 'Build-OS' : "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}") 31 | } 32 | baseName 'org.jlibrtp.demo' 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RTP Library for Java 2 | 3 | jlibrtp aims to create a library that makes it easy to support RTP (RFC 3550,3551) in Java applications. SRTP (RFC 3771) has been delayed in favor of RFC 4585. 4 | 5 | In order to increase compatibility, this library is compiled with JDK1.8. 6 | 7 | ## Include from from Maven 8 | 9 | Configure maven to use Central from your Project Object Model (POM) file.You may do so by 10 | adding the following to your pom.xml: 11 | 12 | 13 | 14 | central 15 | Maven Central 16 | default 17 | https://repo1.maven.org/maven2 18 | 19 | false 20 | 21 | 22 | 23 | 24 | Add jlibrtp as a dependecy to your pom.xml 25 | 26 | 27 | org.jvoicexml 28 | org.jlibrtp 29 | 0.2 30 | module 31 | 32 | 33 | ## Include from Gradle 34 | 35 | Add the Maven Central repository to your build.gradle 36 | 37 | repositories { 38 | mavenCentral() 39 | } 40 | 41 | Add jlibrtp as a an implementation dependency to your build.gradle 42 | 43 | implementation 'org.jvoicexml:org.librtp:0.2' 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, jlibrtp 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/README.txt: -------------------------------------------------------------------------------- 1 | jlibrtp - Java RTP Library 2 | 3 | Kepp, Arne 4 | ak2618@columbia.edu 5 | 6 | Columbia University 7 | New York, NY 10027 8 | USA 9 | 10 | This library was started as a term project in VoIP Security, a class taught by 11 | Prof. Henning Schulzrinne at Columbia University. Version 0.1 (not released as such) 12 | was written by Vaishnav Janardhan (vj2135@columbia.edu) and Arne Kepp (ak2618@columbia.edu). 13 | 14 | This version was rewritten by Arne Kepp, as a student project under the supervision of 15 | Prof. Henning Schulzrinne, Columbia University. 16 | 17 | ------Abstract 18 | jlibrtp is a library that implements the Real-Time Transport Protocol (RTP), 19 | a well-established standard for streaming media across IP-based networks, in Java. 20 | The purpose of this library is to make it easy for application developers to 21 | create applications for peer to peer streaming of audio, video and other data. 22 | In addition, developers will need a protocol to establish contact with peers, 23 | such as Session Initialization Protocol (SIP) and/or SDP. 24 | 25 | The library accepts any kind of binary data, handles packet parsing and reordering, 26 | maintains a participant database and the control connection associated with the 27 | protocol. The application is notified of received data through a callback-interface. 28 | The library supports IPv4, IPv6 and multicast. It does currently not support encryption, 29 | and should not be used in cases where confidentiality is important before this has 30 | been remedied. 31 | 32 | Please refer to http://jlibrtp.org for more information and newer versions. 33 | 34 | The library requires Sun Microsystems Java 1.5.0 or greater, or equivalent. 35 | 36 | The Library is licensed under the GNU Lesser General Public License, see LICENSE.txt 37 | 38 | The demonstration programs can be compiled as follows: 39 | javac ./jlibrtpDemos/SoundSenderDemo.java jlibrtp/*.java -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/PktBufNode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | /** 22 | * This is a four-directional data structures used for 23 | * the frame buffer, i.e. buffer for pkts that need 24 | * to be assimilated into complete frames. 25 | * 26 | * All the actual work is done by PktBuffer. 27 | * 28 | * @author Arne Kepp 29 | * 30 | */ 31 | public class PktBufNode { 32 | /** The next node (RTP Timestamp), looking from the back: next means older */ 33 | protected PktBufNode nextFrameQueueNode = null; 34 | /** The previous node (RTP Timestmap), looking from the back: prev means newer */ 35 | protected PktBufNode prevFrameQueueNode = null; 36 | /** The next node within the frame, i.e. higher sequence number, same RTP timestamp */ 37 | protected PktBufNode nextFrameNode = null; 38 | /** Number of packets with the same RTP timestamp */ 39 | protected int pktCount; 40 | /** The RTP timeStamp associated with this node */ 41 | protected long timeStamp; 42 | /** The sequence number associated with this node */ 43 | protected int seqNum; 44 | /** The payload, a parsed RTP Packet */ 45 | protected RtpPkt pkt = null; 46 | 47 | /** 48 | * Create a new packet buffer node based on a packet 49 | * @param aPkt the packet 50 | */ 51 | protected PktBufNode(RtpPkt aPkt) { 52 | pkt = aPkt; 53 | timeStamp = aPkt.getTimeStamp(); 54 | seqNum = aPkt.getSeqNumber(); 55 | pktCount = 1; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /org.jlibrtp/src/test/java/org/jlibrtp/validateccrtp/CCRTPReceiver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.validateccrtp; 20 | 21 | import java.net.DatagramSocket; 22 | 23 | import org.jlibrtp.DataFrame; 24 | import org.jlibrtp.Participant; 25 | import org.jlibrtp.RTPAppIntf; 26 | import org.jlibrtp.RTPSession; 27 | 28 | /** 29 | * Receives and prints packets sent by the rtpsend demo program in ccrtp 1.5.x 30 | * 31 | * Send them to port 6003, unless you modify this program. 32 | * 33 | * @author Arne Kepp 34 | * 35 | */ 36 | 37 | public class CCRTPReceiver implements RTPAppIntf { 38 | RTPSession rtpSession = null; 39 | 40 | public CCRTPReceiver() { 41 | // Do nothing; 42 | } 43 | 44 | public void receiveData(DataFrame frame, Participant p) { 45 | System.out.println("Got data: " + new String(frame.getConcatenatedData())); 46 | } 47 | 48 | public void userEvent(int type, Participant[] participant) { 49 | //Do nothing 50 | } 51 | 52 | public int frameSize(int payloadType) { 53 | return 1; 54 | } 55 | 56 | /** 57 | * @param args 58 | */ 59 | public static void main(String[] args) { 60 | CCRTPReceiver me = new CCRTPReceiver(); 61 | 62 | DatagramSocket rtpSocket = null; 63 | DatagramSocket rtcpSocket = null; 64 | 65 | try { 66 | rtpSocket = new DatagramSocket(16384); 67 | rtcpSocket = new DatagramSocket(16385); 68 | } catch (Exception e) { 69 | System.out.println("RTPSession failed to obtain port"); 70 | } 71 | 72 | me.rtpSession = new RTPSession(rtpSocket, rtcpSocket); 73 | me.rtpSession.naivePktReception(true); 74 | me.rtpSession.registerRTPSession(me,null,null); 75 | 76 | Participant p = new Participant("127.0.0.1",16386,16387); 77 | me.rtpSession.addParticipant(p); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/ValidateParticipantDatabase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.net.DatagramSocket; 22 | import java.net.InetAddress; 23 | 24 | /** 25 | * Tests for the {@link ParticipantDatabase} 26 | * @author Arne Kepp 27 | * 28 | */ 29 | public class ValidateParticipantDatabase { 30 | 31 | /** 32 | * Main method. 33 | * @param args command line arguments 34 | */ 35 | public static void main(String[] args) { 36 | DatagramSocket rtpSocket = null; 37 | DatagramSocket rtcpSocket = null; 38 | try { 39 | rtpSocket = new DatagramSocket(6002); 40 | rtcpSocket = new DatagramSocket(6003); 41 | } catch (Exception e) { 42 | System.out.println("RTPSession failed to obtain port"); 43 | } 44 | RTPSession rtpSession = new RTPSession(rtpSocket, rtcpSocket); 45 | 46 | ParticipantDatabase partDb = new ParticipantDatabase(rtpSession); 47 | 48 | Participant part0 = new Participant("127.0.0.1", 4545, 4555); 49 | Participant part1 = new Participant("127.0.0.1", 4546, 4556); 50 | Participant part2 = new Participant("127.0.0.1", 4547, 4556); 51 | 52 | partDb.addParticipant(0,part0); 53 | partDb.addParticipant(0,part1); 54 | partDb.addParticipant(0,part2); 55 | 56 | partDb.debugPrint(); 57 | 58 | System.out.println("********************* Removing Participant 1 (4546) ***********************"); 59 | partDb.removeParticipant(part1); 60 | partDb.debugPrint(); 61 | 62 | 63 | InetAddress inetAdr = null; 64 | try { inetAdr = InetAddress.getByName("127.0.0.1"); } catch (Exception e) { }; 65 | 66 | //Participant part3 = partDb.getParticipant(inetAdr); 67 | //part3.ssrc = 12345678; 68 | System.out.println("********************* Updating Participant 3 (4546) ***********************"); 69 | //partDb.updateParticipant(part3); 70 | 71 | partDb.debugPrint(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /org.jlibrtp/src/test/java/org/jlibrtp/validateccrtp/CCRTPSender.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.validateccrtp; 20 | 21 | import java.net.DatagramSocket; 22 | 23 | import org.jlibrtp.DataFrame; 24 | import org.jlibrtp.Participant; 25 | import org.jlibrtp.RTPAppIntf; 26 | import org.jlibrtp.RTPSession; 27 | 28 | /** 29 | * Sends packet to the rtplisten demo program in ccrtp 1.5.x 30 | * 31 | * Listen on port 6004, unless you modify this program. 32 | * 33 | * @author Arne Kepp 34 | * 35 | */ 36 | 37 | public class CCRTPSender implements RTPAppIntf { 38 | RTPSession rtpSession = null; 39 | 40 | public CCRTPSender() { 41 | // Do nothing; 42 | } 43 | 44 | public void receiveData(DataFrame frame, Participant p) { 45 | System.out.println("Got data: " + new String(frame.getConcatenatedData())); 46 | } 47 | 48 | public void userEvent(int type, Participant[] participant) { 49 | //Do nothing 50 | } 51 | 52 | public int frameSize(int payloadType) { 53 | return 1; 54 | } 55 | 56 | /** 57 | * @param args 58 | */ 59 | public static void main(String[] args) { 60 | CCRTPSender me = new CCRTPSender(); 61 | 62 | DatagramSocket rtpSocket = null; 63 | DatagramSocket rtcpSocket = null; 64 | 65 | try { 66 | rtpSocket = new DatagramSocket(16384); 67 | rtcpSocket = new DatagramSocket(16385); 68 | } catch (Exception e) { 69 | System.out.println("RTPSession failed to obtain port"); 70 | } 71 | 72 | me.rtpSession = new RTPSession(rtpSocket, rtcpSocket); 73 | me.rtpSession.naivePktReception(true); 74 | me.rtpSession.registerRTPSession(me,null,null); 75 | 76 | Participant p = new Participant("127.0.0.1", 16386, 16387); 77 | me.rtpSession.addParticipant(p); 78 | 79 | //me.rtpSession.setPayloadType(0); 80 | 81 | for(int i=0; i<10; i++) { 82 | String str = "Test number " + i; 83 | me.rtpSession.sendData(str.getBytes()); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/protocols/rtp/Handler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | package org.jlibrtp.protocols.rtp; 19 | 20 | import java.io.IOException; 21 | import java.net.InetAddress; 22 | import java.net.URISyntaxException; 23 | import java.net.URL; 24 | import java.net.URLConnection; 25 | import java.net.URLStreamHandler; 26 | import java.net.UnknownHostException; 27 | import java.util.logging.Logger; 28 | 29 | 30 | /** 31 | *

Title: Handler for rtp:// protocol

32 | * 33 | *

Description:

34 | * 35 | *

Copyright: Copyright (c) 2007-2008

36 | * 37 | *

Company: VoiceInteraction

38 | * 39 | * @author Renato Cassaca 40 | * @version 1.0 41 | */ 42 | public class Handler extends URLStreamHandler { 43 | /** Logger instance. */ 44 | private static final Logger LOGGER = 45 | Logger.getLogger(Handler.class.getName()); 46 | 47 | public Handler() { 48 | super(); 49 | } 50 | 51 | protected URLConnection openConnection(URL url) throws IOException { 52 | try { 53 | return new RTPURLConnection(url); 54 | } catch (URISyntaxException ex) { 55 | throw new IOException("Invalid provided URL"); 56 | } 57 | } 58 | 59 | /** 60 | * Returns the default port for a URL parsed by this handler. 61 | * 62 | * @return the default port for a URL parsed by this handler. 63 | */ 64 | protected int getDefaultPort() { 65 | return 0; 66 | } 67 | 68 | /** 69 | * Get the IP address of our host. 70 | * 71 | * @param u a URL object 72 | * @return an InetAddress representing the host IP address. 73 | */ 74 | protected synchronized InetAddress getHostAddress(URL u) { 75 | try { 76 | return InetAddress.getLocalHost(); 77 | } catch (UnknownHostException ex) { 78 | LOGGER.warning(ex.getMessage()); 79 | return null; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RTPAppIntf.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | package org.jlibrtp; 21 | 22 | 23 | /** 24 | * This is the callback interface for RTP packets. 25 | * 26 | * It is mandatory, but you can inore the data if you like. 27 | * 28 | * @author Arne Kepp 29 | */ 30 | public interface RTPAppIntf { 31 | 32 | /** 33 | * The callback method through which the application will receive 34 | * data from jlibrtp. These calls are synchronous, so you will not 35 | * receive any new packets until this call returns. 36 | * 37 | * @param frame the frame containing the data 38 | * @param participant the participant from which the data came 39 | */ 40 | public void receiveData(DataFrame frame, Participant participant); 41 | 42 | 43 | /** 44 | * The callback method through which the application will receive 45 | * notifications about user updates, additions and byes. 46 | * Types: 47 | * 1 - Bye 48 | * 2 - New through RTP, check .getRtpSendSock() 49 | * 3 - New through RTCP, check .getRtcpSendSock() 50 | * 4 - SDES packet received, check the getCname() etc methods 51 | * 5 - Matched SSRC to ip-address provided by application 52 | * 53 | * @param type the type of event 54 | * @param participant the participants in question 55 | */ 56 | public void userEvent(int type, Participant[] participant); 57 | 58 | /** 59 | * The callback method through which the application can specify 60 | * the number of packets that make up a frame for a given payload type. 61 | * 62 | * A negative value denotes frames of variable length, so jlibrtp 63 | * will return whatever it has at the time. 64 | * 65 | * In most applications, this function can simply return 1. 66 | * 67 | * This should be implemented as something fast, such as an 68 | * integer array with the indexes being the payload type. 69 | * 70 | * @param payloadType the payload type specified in the RTP packet 71 | * @return the number of packets that make up a frame 72 | */ 73 | public int frameSize(int payloadType); 74 | } 75 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/DebugAppIntf.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | import java.net.InetSocketAddress; 21 | 22 | /** 23 | * DebugAppIntf can be registered on RTPSession to provide simple 24 | * debugging functionality. This is particularly useful to determine 25 | * whether the client is receing any data at all. 26 | * 27 | * @author Arne Kepp 28 | * 29 | */ 30 | 31 | public interface DebugAppIntf { 32 | /** 33 | * This function wil notify you of any packets received, valid or not. 34 | * Useful for network debugging, and finding bugs in jlibrtp. 35 | * 36 | * Type is an integer describing the type of event 37 | * -2 - Invalid RTCP packet received 38 | * -1 - Invalid RTP packet received 39 | * 0 - RTP packet received 40 | * 1 - RTCP packet received 41 | * 42 | * Description is a string that should be meaningful to advanced users, such as 43 | * "RTP packet received from 127.0.0.1:12312, SSRC: 1380912 , payload type 1, packet size 16 octets" 44 | * or 45 | * "Invalid RTP packet received from 127.0.0.1:12312" 46 | * 47 | * This function is synchonous and should return quickly. 48 | * 49 | * @param type , the type of event, see above. 50 | * @param socket , taken directly from the UDP packet 51 | * @param description , see above. 52 | */ 53 | public void packetReceived(int type, InetSocketAddress socket, String description); 54 | 55 | /** 56 | * This function will notify you of any packets sent from this instance of RTPSession. 57 | * Useful for network debugging, and finding bugs in jlibrtp. 58 | * 59 | * Type is an integer describing the type of event 60 | * 0 - RTP unicast packet sent 61 | * 1 - RTP multicast packet sent 62 | * 2 - RTCP unicast packet sent 63 | * 3 - RTCP multicast packet sent 64 | * 65 | * Description is a string that should be meaningful to advanced users, such as 66 | * 67 | * This function is synchonous and should return quickly. 68 | * 69 | * @param type , the type of event, see above 70 | * @param socket , taken directly from the UDP packet 71 | * @param description , see above 72 | */ 73 | public void packetSent(int type, InetSocketAddress socket, String description); 74 | 75 | /** 76 | * Other important events that can occur in session 77 | * -1 SSRC conflict 78 | * 0 Session is terminating 79 | * @param type see above 80 | * @param description , see above 81 | */ 82 | public void importantEvent(int type, String description); 83 | } 84 | -------------------------------------------------------------------------------- /org.jlibrtp/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'signing' 4 | id 'maven-publish' 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | sourceCompatibility = 1.8 12 | targetCompatibility = 1.8 13 | 14 | dependencies { 15 | testImplementation 'junit:junit:4.13.2' 16 | } 17 | 18 | jar { 19 | manifest { 20 | attributes('Implementation-Title': 'RTP Library for Java', 21 | 'Implementation-Vendor': 'switch', 22 | 'Implementation-Version': version, 23 | 'Built-By' : System.properties['user.name'], 24 | 'Build-Timestamp': new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()), 25 | 'Created-By' : "Gradle ${gradle.gradleVersion}", 26 | 'Build-Jdk' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})", 27 | 'Build-OS' : "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}") 28 | } 29 | baseName 'org.jlibrtp' 30 | } 31 | 32 | java { 33 | withJavadocJar() 34 | withSourcesJar() 35 | } 36 | 37 | publishing { 38 | publications { 39 | mavenJava(MavenPublication) { 40 | artifactId = tasks.jar.baseName 41 | from components.java 42 | versionMapping { 43 | usage('java-api') { 44 | fromResolutionOf('runtimeClasspath') 45 | } 46 | usage('java-runtime') { 47 | fromResolutionResult() 48 | } 49 | } 50 | pom { 51 | name = 'jlibrtp' 52 | description = 'RTP Library for Java' 53 | url = 'https://github.com/JVoiceXML/jlibrtp' 54 | licenses { 55 | license { 56 | name = 'GNU Lesser General Public License, Version 2.1' 57 | url = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt' 58 | } 59 | } 60 | developers { 61 | developer { 62 | id = 'schnelle' 63 | name = 'Dirk Schnelle-Walka' 64 | email = 'dirk.schnelle@jvoicexml.org' 65 | } 66 | } 67 | scm { 68 | connection = 'scm:git:git@github.com:JVoiceXML/jlibrtp.git' 69 | developerConnection = 'scm:git:ssh://github.com:JVoiceXML/JVoiceXML.git' 70 | url = 'https://github.com/JVoiceXML/jlibrtp' 71 | } 72 | } 73 | } 74 | } 75 | repositories { 76 | maven { 77 | def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 78 | def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" 79 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 80 | credentials { 81 | username = JVOICEXML_OSSRH_USERNAME 82 | password = JVOICEXML_OSSRH_PASSWORD 83 | } 84 | } 85 | } 86 | } 87 | 88 | signing { 89 | sign publishing.publications.mavenJava 90 | } 91 | 92 | javadoc { 93 | if(JavaVersion.current().isJava9Compatible()) { 94 | options.addBooleanOption('html5', true) 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /org.jlibrtp/src/test/java/org/jlibrtp/test/TestRTPSession.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.test; 20 | import java.net.DatagramSocket; 21 | 22 | import org.jlibrtp.DataFrame; 23 | import org.jlibrtp.Participant; 24 | import org.jlibrtp.RTPAppIntf; 25 | import org.jlibrtp.RTPSession; 26 | 27 | public class TestRTPSession implements RTPAppIntf { 28 | public RTPSession rtpSession = null; 29 | 30 | TestRTPSession() { 31 | DatagramSocket rtpSocket = null; 32 | DatagramSocket rtcpSocket = null; 33 | 34 | try { 35 | rtpSocket = new DatagramSocket(6002); 36 | rtcpSocket = new DatagramSocket(6003); 37 | } catch (Exception e) { 38 | System.out.println("RTPSession failed to obtain port"); 39 | } 40 | 41 | 42 | rtpSession = new RTPSession(rtpSocket, rtcpSocket); 43 | 44 | rtpSession.registerRTPSession(this,null,null); 45 | 46 | 47 | Participant p = new Participant("127.0.0.1", 6004, 6005); 48 | 49 | rtpSession.addParticipant(p); 50 | } 51 | 52 | 53 | public void receiveData(DataFrame frame, Participant p) { 54 | String s = new String(frame.getConcatenatedData()); 55 | System.out.println("The Data has been received: "+s+" , thank you " 56 | +p.getCNAME()+"("+p.getSSRC()+")"); 57 | } 58 | 59 | public void userEvent(int type, Participant[] participant) { 60 | //Do nothing 61 | } 62 | 63 | public int frameSize(int payloadType) { 64 | return 1; 65 | } 66 | 67 | public static void main(String[] args) { 68 | TestRTPSession test = new TestRTPSession(); 69 | //try { Thread.currentThread().sleep(10000); } catch (Exception e) { }; 70 | long teststart = System.currentTimeMillis(); 71 | String str = "abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd abce abcd "; 72 | byte[] data = str.getBytes(); 73 | System.out.println(data.length); 74 | 75 | int i=0; 76 | while(i<100000) { 77 | test.rtpSession.sendData(data); 78 | //try { Thread.currentThread().sleep(500); } catch (Exception e) { }; 79 | i++; 80 | } 81 | 82 | long testend = System.currentTimeMillis(); 83 | //String str = "efgh"; 84 | 85 | //test.rtpSession.sendData(str.getBytes()); 86 | 87 | System.out.println("" + (testend - teststart)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RTCPAVPFIntf.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | package org.jlibrtp; 21 | 22 | 23 | /** 24 | * This is the callback interface for the AVPF profile (RFC 4585) 25 | * 26 | * It is optional, you do not have to register it. 27 | * 28 | * If there are specific events you wish to ignore, 29 | * you can simply implement empty functions. 30 | * 31 | * These are all syncrhonous, make sure to return quickly 32 | * or do the handling in a new thread. 33 | * 34 | * @author Arne Kepp 35 | */ 36 | public interface RTCPAVPFIntf { 37 | 38 | /** 39 | * This function is called when a 40 | * Picture Loss Indication (PLI, FMT = 1) is received 41 | * 42 | * @param ssrcPacketSender the SSRC of the participant reporting loss of picture 43 | */ 44 | public void PSFBPktPictureLossReceived( 45 | long ssrcPacketSender); 46 | 47 | /** 48 | * This function is called when a 49 | * Slice Loss Indication (SLI, FMT=2) is received 50 | * 51 | * @param ssrcPacketSender the SSRC of the participant reporting loss of slice(s) 52 | * @param sliceFirst macroblock address of first macroblock 53 | * @param sliceNumber number of lost macroblocks, in scan order 54 | * @param slicePictureId the six least significant bits of the picture identifier 55 | */ 56 | public void PSFBPktSliceLossIndic( 57 | long ssrcPacketSender, 58 | int[] sliceFirst, int[] sliceNumber, int[] slicePictureId); 59 | 60 | /** 61 | * This function is called when a 62 | * Reference Picture Selection Indication (RPSI, FMT=3) is received 63 | * 64 | * @param ssrcPacketSender the SSRC of the participant reporting the selection 65 | * @param rpsiPayloadType the RTP payload type related to the RPSI bit string 66 | * @param rpsiBitString the RPSI information as natively defined by the video codec 67 | * @param rpsiPaddingBits the number of padding bits at the end of the string 68 | */ 69 | public void PSFBPktRefPictureSelIndic( 70 | long ssrcPacketSender, 71 | int rpsiPayloadType, byte[] rpsiBitString, int rpsiPaddingBits); 72 | 73 | /** 74 | * This function is called when a 75 | * Transport Layer Feedback Messages is received 76 | * 77 | * @param ssrcPacketSender SSRC of the packet sender 78 | * @param alfBitString message 79 | */ 80 | public void PSFBPktAppLayerFBReceived( 81 | long ssrcPacketSender, 82 | byte[] alfBitString); 83 | 84 | /** 85 | * This function is called when a 86 | * Transport Layer Feedback Messages is received 87 | * 88 | * @param ssrcPacketSender SSRC of packet sender 89 | * @param FMT 1: NACK, 0,2-30: unassigned, 31: reserved 90 | * @param packetID the RTP sequence number of the lost packet 91 | * @param bitmaskLostPackets the bitmask of following lost packets 92 | */ 93 | public void RTPFBPktReceived( 94 | long ssrcPacketSender, 95 | int FMT, int[] packetID, int[] bitmaskLostPackets); 96 | } 97 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RtcpPktAPP.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * Application specific RTCP packets 26 | * 27 | * @author Arne Kepp 28 | */ 29 | public class RtcpPktAPP extends RtcpPkt { 30 | /** Logger instance. */ 31 | private static final Logger LOGGER = 32 | Logger.getLogger(RtcpPktAPP.class.getName()); 33 | 34 | /** Name of packet, 4 bytes ASCII */ 35 | protected byte[] pktName = null; 36 | /** Data of packet */ 37 | protected byte[] pktData = null; 38 | 39 | /** 40 | * Constructor for a new Application RTCP packet 41 | * 42 | * @param ssrc the SSRC of the sender, presumably taken from RTPSession 43 | * @param subtype the subtype of packet, application specific 44 | * @param pktName byte[4] representing ASCII name of packet 45 | * @param pktData the byte[4x] data that represents the message itself 46 | */ 47 | protected RtcpPktAPP(long ssrc, int subtype, byte[] pktName, byte[] pktData) { 48 | // Fetch all the right stuff from the database 49 | super.ssrc = ssrc; 50 | super.packetType = 204; 51 | super.itemCount = subtype; 52 | this.pktName = pktName; 53 | this.pktData = pktData; 54 | } 55 | 56 | /** 57 | * Constructor that parses a received Application RTCP packet 58 | * 59 | * @param aRawPkt the raw packet containing the date 60 | * @param start where in the raw packet this packet starts 61 | */ 62 | protected RtcpPktAPP(byte[] aRawPkt, int start) { 63 | super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt,4); 64 | super.rawPkt = aRawPkt; 65 | 66 | if(!super.parseHeaders(start) || packetType != 204 ) { 67 | if(LOGGER.isLoggable(Level.FINEST)) { 68 | LOGGER.finest(" <-> RtcpPktAPP.parseHeaders() etc. problem"); 69 | } 70 | super.problem = -204; 71 | } else { 72 | //System.out.println("super.length: " + super.length); 73 | if(super.length > 1) { 74 | pktName = new byte[4]; 75 | System.arraycopy(aRawPkt, 8, pktName, 0, 4); 76 | } 77 | if(super.length > 2) { 78 | pktData = new byte[(super.length+1)*4 - 12]; 79 | System.arraycopy(aRawPkt, 12, pktData, 0, pktData.length); 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Encode the packet into a byte[], saved in .rawPkt 86 | * 87 | * CompRtcpPkt will call this automatically 88 | */ 89 | protected void encode() { 90 | super.rawPkt = new byte[12 + this.pktData.length]; 91 | byte[] tmp = StaticProcs.uIntLongToByteWord(super.ssrc); 92 | System.arraycopy(tmp, 0, super.rawPkt, 4, 4); 93 | System.arraycopy(this.pktName, 0, super.rawPkt, 8, 4); 94 | System.arraycopy(this.pktData, 0, super.rawPkt, 12, this.pktData.length); 95 | writeHeaders(); 96 | //System.out.println("ENCODE: " + super.length + " " + rawPkt.length + " " + pktData.length); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/ValidatePktBuffer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.net.DatagramSocket; 22 | 23 | 24 | /** 25 | * Validates the PktBuffer and associated classes. 26 | * 27 | * @author Arne Kepp 28 | * 29 | */ 30 | public class ValidatePktBuffer { 31 | 32 | /** 33 | * Instantiates a buffer, creates some packets, adds them and sorts them. 34 | * @param args command line arguments 35 | */ 36 | public static void main(String[] args) { 37 | // TODO Auto-generated method stub 38 | DatagramSocket rtpSocket = null; 39 | DatagramSocket rtcpSocket = null; 40 | try { 41 | rtpSocket = new DatagramSocket(6002); 42 | rtcpSocket = new DatagramSocket(6003); 43 | } catch (Exception e) { 44 | System.out.println("RTPSession failed to obtain port"); 45 | } 46 | RTPSession rtpSession = new RTPSession(rtpSocket, rtcpSocket); 47 | 48 | 49 | String str1 = "ab"; 50 | String str2 = "cd"; 51 | String str3 = "ef"; 52 | String str4 = "gh"; 53 | String str5 = "ij"; 54 | String str6 = "kl"; 55 | //String str7 = "mn"; 56 | 57 | long syncSource1 = 1; 58 | int seqNumber1 = 1; 59 | //int seqNumber2 = 1; 60 | RtpPkt pkt1 = new RtpPkt(10, syncSource1, 1, 0, str1.getBytes()); 61 | RtpPkt pkt2 = new RtpPkt(20, syncSource1, 2, 0, str2.getBytes()); 62 | RtpPkt pkt3 = new RtpPkt(30, syncSource1, 3, 0, str3.getBytes()); 63 | RtpPkt pkt4 = new RtpPkt(40, syncSource1, 4, 0, str4.getBytes()); 64 | RtpPkt pkt6 = new RtpPkt(60, syncSource1, 6, 0, str5.getBytes()); 65 | RtpPkt pkt7 = new RtpPkt(70, syncSource1, 7, 0, str6.getBytes()); 66 | 67 | Participant p = new Participant(); 68 | 69 | PktBuffer pktBuf = new PktBuffer(rtpSession, p, pkt1); 70 | pktBuf.addPkt(pkt3); //2 71 | pktBuf.addPkt(pkt2); //3 72 | DataFrame aFrame = pktBuf.popOldestFrame(); 73 | String outStr = new String(aFrame.getConcatenatedData()); 74 | System.out.println("** 1 Data from first frame: " + outStr + ", should be ab"); 75 | pktBuf.addPkt(pkt4); //3 76 | pktBuf.addPkt(pkt7); //4 77 | System.out.println("** 1.5 sixth"); 78 | pktBuf.addPkt(pkt6); //5 79 | System.out.println("** 2 Duplicate, should be dropped"); 80 | pktBuf.addPkt(pkt3); //5 81 | // Pop second frame 82 | aFrame = pktBuf.popOldestFrame(); //4 83 | outStr = new String(aFrame.getConcatenatedData()); 84 | System.out.println("** 3 Data from second frame: " + outStr + ", should be cd"); 85 | 86 | // Pop third frame 87 | aFrame = pktBuf.popOldestFrame(); //3 88 | outStr = new String(aFrame.getConcatenatedData()); 89 | System.out.println("** 4 Data from third frame: " + outStr + ", should be ef"); 90 | System.out.println("** 5 pktBuf.getLength is " + pktBuf.getLength() + ", should be 3"); 91 | 92 | System.out.println("** 6 Late arrival, should be dropped"); 93 | pktBuf.addPkt(pkt2); 94 | 95 | aFrame = pktBuf.popOldestFrame(); 96 | outStr = new String(aFrame.getConcatenatedData()); 97 | System.out.println("** 7 Data from fourth frame: " + outStr + ", should be gh"); 98 | 99 | aFrame = pktBuf.popOldestFrame(); 100 | outStr = new String(aFrame.getConcatenatedData()); 101 | System.out.println("** 8 Data from fifth frame: " + outStr + ", should be ij"); 102 | 103 | aFrame = pktBuf.popOldestFrame(); 104 | outStr = new String(aFrame.getConcatenatedData()); 105 | System.out.println("** 9 Data from fifth frame: " + outStr + ", should be kl"); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/ValidateStaticProcs.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | /** 22 | * Validates the StaticProcs. 23 | * 24 | * @author Arne Kepp 25 | * 26 | */ 27 | public class ValidateStaticProcs { 28 | 29 | /** 30 | * Main method. 31 | * @param args command line arguments 32 | */ 33 | public static void main(String[] args) { 34 | // TODO Auto-generated method stub 35 | long one = 100; 36 | long two = 1; 37 | long three = 9999000; 38 | 39 | byte aByte = (byte) 7; 40 | System.out.println("aByte.hex: " + StaticProcs.hexOfByte(aByte)); 41 | 42 | //byte[] oneb = StaticProcs.longToByteWord(one); 43 | byte[] twob = StaticProcs.uIntLongToByteWord(two); 44 | //byte[] threeb = StaticProcs.longToByteWord(three); 45 | 46 | for(int i = 0; i< 4; i++) { 47 | StaticProcs.printBits(twob[i]); 48 | } 49 | //one = StaticProcs.combineBytes(oneb[0], oneb[1], oneb[2], oneb[3]); 50 | two = StaticProcs.bytesToUIntLong(twob,0); 51 | //three = StaticProcs.combineBytes(threeb[0], threeb[1], threeb[2], threeb[3]); 52 | 53 | System.out.println(" one " + one + " two " + two + " three " + three); 54 | 55 | twob = StaticProcs.uIntLongToByteWord(two); 56 | 57 | for(int i = 0; i< 4; i++) { 58 | StaticProcs.printBits(twob[i]); 59 | } 60 | 61 | byte[] bytes = new byte[2]; 62 | int check = 0; 63 | for(int i=0; i< 65536; i++) { 64 | bytes = StaticProcs.uIntIntToByteWord(i); 65 | check = StaticProcs.bytesToUIntInt(bytes, 0); 66 | if(check != i) { 67 | System.out.println(" oops:" + check +" != "+ i); 68 | StaticProcs.printBits(bytes[0]); 69 | StaticProcs.printBits(bytes[1]); 70 | } 71 | } 72 | int a = 65534; 73 | bytes = StaticProcs.uIntIntToByteWord(a); 74 | StaticProcs.printBits(bytes[0]); 75 | StaticProcs.printBits(bytes[1]); 76 | check = StaticProcs.bytesToUIntInt(bytes, 0); 77 | System.out.println(check); 78 | 79 | byte[] arbytes = new byte[22]; 80 | arbytes[13] = -127; 81 | arbytes[14] = 127; 82 | arbytes[15] = -1; 83 | arbytes[16] = 127; 84 | arbytes[17] = -127; 85 | System.out.println("arbitrary length:"); 86 | StaticProcs.printBits(arbytes[14]); 87 | StaticProcs.printBits(arbytes[15]); 88 | StaticProcs.printBits(arbytes[16]); 89 | //long arbTest = StaticProcs.bytesToUintLong(arbytes, 14, 16); 90 | //byte[] reArBytes = StaticProcs.uIntLongToByteWord(arbTest); 91 | //System.out.println("arbitrary length recode: " + Long.toString(arbTest)); 92 | //StaticProcs.printBits(reArBytes[0]); 93 | //StaticProcs.printBits(reArBytes[1]); 94 | //StaticProcs.printBits(reArBytes[2]); 95 | //StaticProcs.printBits(reArBytes[3]); 96 | 97 | byte[] tmp = new byte[4]; 98 | tmp[0] = -127; 99 | tmp[1] = 127; 100 | tmp[2] = -49; 101 | tmp[3] = -1; 102 | 103 | String str2 = ""; 104 | for(int i=0; iTitle: jlibrtp

31 | * 32 | *

Description:

33 | * 34 | *

Copyright: Copyright (c) 2007-2008

35 | * 36 | *

Company: VoiceInteraction

37 | * 38 | * @author Renato Cassaca 39 | * @version 1.0 40 | */ 41 | public class TestRTPURLMultiSender { 42 | 43 | static { 44 | registerProtocolHandlers(); 45 | } 46 | 47 | private static void registerProtocolHandlers() { 48 | //Register protocol handler 49 | String javaPropName = "java.protocol.handler.pkgs"; 50 | 51 | //Start value 52 | System.out.println(javaPropName + " = " + 53 | System.getProperty(javaPropName)); 54 | 55 | //Vou actualizar a propriedade que define o meu protocol handler (URL) 56 | String packageName = "org.jlibrtp.protocols"; 57 | System.setProperty(javaPropName, packageName); 58 | 59 | //Value after update 60 | System.out.println(javaPropName + " = " + 61 | System.getProperty(javaPropName)); 62 | } 63 | 64 | 65 | public TestRTPURLMultiSender() { 66 | super(); 67 | } 68 | 69 | public static void main(String[] args) { 70 | 71 | TestRTPURLMultiSender testrtpurlmultisender = new TestRTPURLMultiSender(); 72 | testrtpurlmultisender.doIt(); 73 | } 74 | 75 | /** 76 | * doIt 77 | */ 78 | private void doIt() { 79 | try { 80 | // This block configure the logger with handler and formatter 81 | /* FileHandler fh = new FileHandler("Sender.log", false); 82 | Logger logger = Logger.getLogger("org.jlibrtp"); 83 | logger.addHandler(fh); 84 | logger.setLevel(Level.ALL); 85 | SimpleFormatter formatter = new SimpleFormatter(); 86 | fh.setFormatter(formatter);*/ 87 | 88 | long sTime = System.currentTimeMillis(); 89 | 90 | URL sendURL = new URL("rtp://172.16.4.42:29000/audio?participant=localhost:30000"); 91 | URLConnection sendC = sendURL.openConnection(); 92 | sendC.connect(); 93 | OutputStream rtpOS = sendC.getOutputStream(); 94 | 95 | for (int i = 0; i < 5; i++) { 96 | 97 | InputStream is = new FileInputStream("capture.raw"); 98 | 99 | byte[] buffer = new byte[1024]; 100 | int br; 101 | while ((br = is.read(buffer)) != -1) { 102 | rtpOS.write(buffer, 0, br); 103 | } 104 | 105 | is.close(); 106 | 107 | System.out.println("Will sleep before sending ith: " + (i+1)); 108 | try { 109 | Thread.sleep(5000); 110 | } catch (InterruptedException ex1) { 111 | } 112 | } 113 | 114 | rtpOS.flush(); 115 | rtpOS.close(); 116 | 117 | System.out.println("Finished Sender: " + (System.currentTimeMillis() - sTime) / 1000); 118 | 119 | } catch (Exception ex) { 120 | ex.printStackTrace(); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /org.jlibrtp/src/test/java/org/jlibrtp/test/protocols/rtp/TestRTPURLSender.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.test.protocols.rtp; 20 | 21 | import java.net.URL; 22 | import java.net.URLConnection; 23 | import java.io.FileInputStream; 24 | import java.io.OutputStream; 25 | import java.io.BufferedInputStream; 26 | import javax.sound.sampled.AudioInputStream; 27 | import javax.sound.sampled.AudioSystem; 28 | import java.util.logging.FileHandler; 29 | import java.util.logging.Logger; 30 | import java.util.logging.Level; 31 | import java.util.logging.SimpleFormatter; 32 | 33 | 34 | /** 35 | *

Title: jlibrtp

36 | * 37 | *

Description:

38 | * 39 | *

Copyright: Copyright (c) 2007-2008

40 | * 41 | *

Company: VoiceInteraction

42 | * 43 | * @author Renato Cassaca 44 | * @version 1.0 45 | */ 46 | public class TestRTPURLSender { 47 | 48 | static { 49 | registerProtocolHandlers(); 50 | } 51 | 52 | private static void registerProtocolHandlers() { 53 | //Register protocol handler 54 | String javaPropName = "java.protocol.handler.pkgs"; 55 | 56 | //Start value 57 | System.out.println(javaPropName + " = " + 58 | System.getProperty(javaPropName)); 59 | 60 | //Vou actualizar a propriedade que define o meu protocol handler (URL) 61 | String packageName = "org.jlibrtp.protocols"; 62 | System.setProperty(javaPropName, packageName); 63 | 64 | //Value after update 65 | System.out.println(javaPropName + " = " + 66 | System.getProperty(javaPropName)); 67 | } 68 | 69 | 70 | public TestRTPURLSender() { 71 | super(); 72 | } 73 | 74 | public static void main(String[] args) { 75 | 76 | TestRTPURLSender testrtpurlsender = new TestRTPURLSender(); 77 | testrtpurlsender.doIt(); 78 | } 79 | 80 | /** 81 | * doIt 82 | */ 83 | private void doIt() { 84 | try { 85 | // This block configure the logger with handler and formatter 86 | FileHandler fh = new FileHandler("Sender.log", false); 87 | Logger logger = Logger.getLogger("org.jlibrtp"); 88 | logger.addHandler(fh); 89 | logger.setLevel(Level.ALL); 90 | SimpleFormatter formatter = new SimpleFormatter(); 91 | fh.setFormatter(formatter); 92 | 93 | long sTime = System.currentTimeMillis(); 94 | 95 | URL sendURL = new URL("rtp://172.16.4.42:29000/audio?participant=localhost:30000&rate=8000"); 96 | URLConnection sendC = sendURL.openConnection(); 97 | sendC.connect(); 98 | OutputStream rtpOS = sendC.getOutputStream(); 99 | 100 | FileInputStream fis = new FileInputStream("capture.wav"); 101 | BufferedInputStream bis = new BufferedInputStream(fis); 102 | AudioInputStream is = AudioSystem.getAudioInputStream(bis); 103 | 104 | byte[] buffer = new byte[1024]; 105 | int br; 106 | while ((br = is.read(buffer)) != -1) { 107 | rtpOS.write(buffer, 0, br); 108 | } 109 | rtpOS.flush(); 110 | rtpOS.close(); 111 | 112 | System.out.println("Finished Sender: " + (System.currentTimeMillis() - sTime) / 1000); 113 | 114 | 115 | } catch (Exception ex) { 116 | ex.printStackTrace(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/demo/UnicastExample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.demo; 20 | 21 | import java.net.DatagramSocket; 22 | 23 | import org.jlibrtp.DataFrame; 24 | import org.jlibrtp.Participant; 25 | import org.jlibrtp.RTPAppIntf; 26 | import org.jlibrtp.RTPSession; 27 | 28 | /** 29 | *

This is an example of how to set up a Unicast session.

30 | *

It does not accept any input arguments and is therefore of limited practical value, but it shows 31 | * the basics.

32 | * 33 | *

The class has to implement RTPAppIntf.

34 | * @author Arne Kepp 35 | */ 36 | public class UnicastExample implements RTPAppIntf { 37 | /** Holds a RTPSession instance */ 38 | RTPSession rtpSession = null; 39 | 40 | /** 41 | * A minimal constructor 42 | * @param rtpSession the session 43 | */ 44 | public UnicastExample(RTPSession rtpSession) { 45 | this.rtpSession = rtpSession; 46 | } 47 | 48 | // RTPAppIntf All of the following are documented in the JavaDocs 49 | /** 50 | * Used to receive data from the RTP Library. We expect no data. 51 | * {@inheritDoc} 52 | */ 53 | public void receiveData(DataFrame frame, Participant p) { 54 | /** 55 | * This concatenates all received packets for a single timestamp 56 | * into a single byte[] 57 | */ 58 | byte[] data = frame.getConcatenatedData(); 59 | 60 | /** 61 | * This returns the CNAME, if any, associated with the SSRC 62 | * that was provided in the RTP packets received. 63 | */ 64 | String cname = p.getCNAME(); 65 | 66 | System.out.println("Received data from " + cname); 67 | System.out.println(new String(data)); 68 | } 69 | 70 | /** 71 | * Used to communicate updates to the user database through RTCP 72 | * {@inheritDoc} 73 | */ 74 | public void userEvent(int type, Participant[] participant) { 75 | //Do nothing 76 | } 77 | 78 | /** 79 | * How many packets make up a complete frame for the payload type? 80 | * {@inheritDoc} 81 | */ 82 | public int frameSize(int payloadType) { 83 | return 1; 84 | } 85 | // RTPAppIntf/ 86 | 87 | 88 | /** 89 | * Main method. 90 | * @param args command line parameters 91 | */ 92 | public static void main(String[] args) { 93 | // 1. Create sockets for the RTPSession 94 | DatagramSocket rtpSocket = null; 95 | DatagramSocket rtcpSocket = null; 96 | try { 97 | rtpSocket = new DatagramSocket(16384); 98 | rtcpSocket = new DatagramSocket(16385); 99 | } catch (Exception e) { 100 | System.out.println("RTPSession failed to obtain port"); 101 | } 102 | 103 | // 2. Create the RTP session 104 | RTPSession rtpSession = new RTPSession(rtpSocket, rtcpSocket); 105 | 106 | // 3. Instantiate the application object 107 | UnicastExample uex = new UnicastExample(rtpSession); 108 | 109 | // 4. Add participants we want to notify upon registration 110 | // a. Hopefully nobody is listening on this port. 111 | Participant part = new Participant("127.0.0.1",16386,16387); 112 | rtpSession.addParticipant(part); 113 | 114 | // 5. Register the callback interface, this launches RTCP threads too 115 | // The two null parameters are for the RTCP and debug interfaces, not use here 116 | rtpSession.registerRTPSession(uex, null, null); 117 | 118 | // Wait 2500 ms, because of the initial RTCP wait 119 | try{ Thread.sleep(2000); } catch(Exception e) {} 120 | 121 | // Note: The wait is optional, but insures SDES packets 122 | // receive participants before continuing 123 | 124 | // 6. Send some data 125 | String str = "Hi there!"; 126 | rtpSession.sendData(str.getBytes()); 127 | 128 | // 7. Terminate the session, takes a few ms to kill threads in order. 129 | rtpSession.endSession(); 130 | //This may result in "Sleep interrupted" messages, ignore them 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/AppCallerThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.Enumeration; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | 25 | /** 26 | * The purpose of this thread is to check whether there are packets ready from 27 | * any participants. 28 | * 29 | * It should sleep when not in use, and be woken up by a condition variable. 30 | * 31 | * Optionally, if we do jitter-control, the condition variable should have a max waiting period 32 | * equal to how often we need to push data. 33 | * 34 | * @author Arne Kepp 35 | */ 36 | public class AppCallerThread extends Thread { 37 | /** Logger instance. */ 38 | private static final Logger LOGGER = 39 | Logger.getLogger(AppCallerThread.class.getName()); 40 | 41 | /** The parent RTP Session */ 42 | RTPSession rtpSession; 43 | /** The applications interface, where the callback methods are called */ 44 | RTPAppIntf appl; 45 | 46 | /** 47 | * Instantiates the AppCallerThread 48 | * 49 | * @param session the RTPSession with participants etc 50 | * @param rtpApp the interface to which data is given 51 | */ 52 | protected AppCallerThread(RTPSession session, RTPAppIntf rtpApp) { 53 | rtpSession = session; 54 | appl = rtpApp; 55 | if(LOGGER.isLoggable(Level.FINEST)) { 56 | LOGGER.finest("<-> AppCallerThread created"); 57 | } 58 | setName("AppCallerThread"); 59 | } 60 | 61 | /** 62 | * The AppCallerThread will run in this loop until the RTPSession 63 | * is terminated. 64 | * 65 | * Whenever an RTP packet is received it will loop over the 66 | * participants to check for packet buffers that have available 67 | * frame. 68 | */ 69 | public void run() { 70 | if(LOGGER.isLoggable(Level.FINER)) { 71 | LOGGER.finer("-> AppCallerThread.run()"); 72 | } 73 | 74 | while(rtpSession.endSession == false) { 75 | 76 | rtpSession.pktBufLock.lock(); 77 | try { 78 | if(LOGGER.isLoggable(Level.FINER)) { 79 | LOGGER.finer("<-> AppCallerThread going to Sleep"); 80 | } 81 | 82 | try { rtpSession.pktBufDataReady.await(); } 83 | catch (Exception e) { LOGGER.log(Level.WARNING, "AppCallerThread:" + e.getMessage(), e);} 84 | 85 | // Next loop over all participants and check whether they have anything for us. 86 | Enumeration enu = rtpSession.partDb.getParticipants(); 87 | 88 | while(enu.hasMoreElements()) { 89 | Participant p = enu.nextElement(); 90 | 91 | boolean done = false; 92 | //System.out.println(p.ssrc + " " + !done +" " + p.rtpAddress 93 | // + " " + rtpSession.naiveReception + " " + p.pktBuffer); 94 | //System.out.println("done: " + done + " p.unexpected: " + p.unexpected); 95 | while(!done && (!p.unexpected || rtpSession.naiveReception) 96 | && p.pktBuffer != null && p.pktBuffer.length > 0) { 97 | 98 | DataFrame aFrame = p.pktBuffer.popOldestFrame(); 99 | if(aFrame == null) { 100 | done = true; 101 | } else { 102 | appl.receiveData(aFrame, p); 103 | } 104 | } 105 | } 106 | 107 | } finally { 108 | rtpSession.pktBufLock.unlock(); 109 | } 110 | 111 | } 112 | if(LOGGER.isLoggable(Level.FINER)) { 113 | LOGGER.finer("<- AppCallerThread.run() terminating"); 114 | } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RtcpPktBYE.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * RTCP packets for sending Bye messages 26 | * 27 | * @author Arne Kepp 28 | */ 29 | public class RtcpPktBYE extends RtcpPkt { 30 | /** Logger instance. */ 31 | private static final Logger LOGGER = 32 | Logger.getLogger(RtcpPktBYE.class.getName()); 33 | 34 | /** SSRCs saying bye, 32xn bits, n<16 */ 35 | protected long[] ssrcArray = null; 36 | /** Optional reason */ 37 | protected byte[] reason = null; 38 | 39 | /** 40 | * Constructs a new object. 41 | * @param ssrcs SSRC of participant 42 | * @param aReason message 43 | */ 44 | protected RtcpPktBYE(long[] ssrcs,byte[] aReason) { 45 | super.packetType = 203; 46 | // Fetch all the right stuff from the database 47 | reason = aReason; 48 | ssrcArray = ssrcs; 49 | if(ssrcs.length < 1) { 50 | LOGGER.warning("RtcpBYE.RtcpPktBYE(long[] ssrcs, byte[] aReason) requires at least one SSRC!"); 51 | } 52 | } 53 | 54 | /** 55 | * Constructs a new object 56 | * @param aRawPkt message 57 | * @param start start point in message 58 | */ 59 | protected RtcpPktBYE(byte[] aRawPkt, int start) { 60 | rawPkt = aRawPkt; 61 | if(!super.parseHeaders(start) || packetType != 203 ) { 62 | if(LOGGER.isLoggable(Level.FINEST)) { 63 | LOGGER.finest(" <-> RtcpPktBYE.parseHeaders() etc. problem"); 64 | } 65 | super.problem = -203; 66 | } else { 67 | ssrcArray = new long[super.itemCount]; 68 | 69 | for(int i=0; i (super.itemCount + 1)) { 73 | int reasonLength = (int) aRawPkt[start + (super.itemCount+1)*4]; 74 | //System.out.println("super.itemCount:"+super.itemCount+" reasonLength:"+reasonLength+" start:"+(super.itemCount*4 + 4 + 1)); 75 | reason = new byte[reasonLength]; 76 | System.arraycopy(aRawPkt, start + (super.itemCount + 1)*4 + 1, reason, 0, reasonLength); 77 | //System.out.println("test:" + new String(reason)); 78 | } 79 | } 80 | } 81 | 82 | protected void encode() { 83 | itemCount = ssrcArray.length; 84 | length = 4*ssrcArray.length; 85 | 86 | if(reason != null) { 87 | length += (reason.length + 1)/4; 88 | if((reason.length + 1) % 4 != 0) { 89 | length +=1; 90 | } 91 | } 92 | rawPkt = new byte[length*4 + 4]; 93 | 94 | int i; 95 | byte[] someBytes; 96 | 97 | // SSRCs 98 | for(i=0; iTitle: jlibrtp

39 | * 40 | *

Description:

41 | * 42 | *

Copyright: Copyright (c) 2007

43 | * 44 | *

Company: VoiceInteraction

45 | * 46 | * @author Renato Cassaca 47 | * @version 1.0 48 | */ 49 | public class TestRTPURLReceiver { 50 | 51 | static { 52 | registerProtocolHandlers(); 53 | } 54 | 55 | private static void registerProtocolHandlers() { 56 | //Register protocol handler 57 | String javaPropName = "java.protocol.handler.pkgs"; 58 | 59 | //Start value 60 | System.out.println(javaPropName + " = " + System.getProperty(javaPropName)); 61 | 62 | //Vou actualizar a propriedade que define o meu protocol handler (URL) 63 | String packageName = "org.jlibrtp.protocols"; 64 | System.setProperty(javaPropName, packageName); 65 | 66 | //Value after update 67 | System.out.println(javaPropName + " = " + System.getProperty(javaPropName)); 68 | } 69 | 70 | 71 | public TestRTPURLReceiver() { 72 | super(); 73 | } 74 | 75 | public static void main(String[] args) { 76 | Logger.getLogger("").setLevel(Level.FINEST); 77 | TestRTPURLReceiver testrtpurlreceiver = new TestRTPURLReceiver(); 78 | testrtpurlreceiver.doIt(); 79 | } 80 | 81 | /** 82 | * doIt 83 | */ 84 | private void doIt() { 85 | try { 86 | // This block configure the logger with handler and formatter 87 | FileHandler fh = new FileHandler("Receiver.log", false); 88 | Logger logger = Logger.getLogger("org.jlibrtp"); 89 | logger.addHandler(fh); 90 | logger.setLevel(Level.ALL); 91 | SimpleFormatter formatter = new SimpleFormatter(); 92 | fh.setFormatter(formatter); 93 | 94 | 95 | AudioFormat receiveFormat = new AudioFormat(AudioFormat.Encoding.ULAW, 96 | 8000, 97 | 8, 98 | 1, 99 | 1, 100 | 8000, 101 | false); 102 | 103 | AudioFormat playFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 104 | 8000, 105 | 16, 106 | 1, 107 | 2, 108 | 8000, 109 | false); 110 | 111 | 112 | Info playbackLineInfo = new Info(SourceDataLine.class, playFormat, AudioSystem.NOT_SPECIFIED); 113 | SourceDataLine sourceLine = (SourceDataLine)AudioSystem.getLine(playbackLineInfo); 114 | System.out.println("Playing to: "+playbackLineInfo); 115 | sourceLine.open(); 116 | sourceLine.start(); 117 | 118 | 119 | URL recvURL = new URL("rtp://localhost:30000/audio?rate=8000&keepAlive=false"); 120 | URLConnection recvC = recvURL.openConnection(); 121 | recvC.connect(); 122 | InputStream rtpIS = recvC.getInputStream(); 123 | 124 | byte[] buffer = new byte[1024]; 125 | int br; 126 | OutputStream os = new FileOutputStream("rtp_received.raw"); 127 | 128 | AudioInputStream receiveStream = new AudioInputStream(rtpIS, receiveFormat, AudioSystem.NOT_SPECIFIED); 129 | AudioInputStream convStream = AudioSystem.getAudioInputStream(playFormat, receiveStream); 130 | 131 | while ((br = convStream.read(buffer)) != -1) { 132 | os.write(buffer, 0, br); 133 | sourceLine.write(buffer, 0, br); 134 | } 135 | 136 | os.close(); 137 | rtpIS.close(); 138 | convStream.close(); 139 | receiveStream.close(); 140 | 141 | System.out.println("Finished Receiver"); 142 | } catch (Exception ex) { 143 | ex.printStackTrace(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/ValidateRtcpPkt.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.net.DatagramSocket; 22 | import java.net.InetSocketAddress; 23 | import java.util.ListIterator; 24 | 25 | /** 26 | * Tests of {@link RtcpPkt}. 27 | * @author Arne Kepp 28 | * 29 | */ 30 | public class ValidateRtcpPkt { 31 | 32 | /** 33 | * Main method. 34 | * @param args command line arguments 35 | */ 36 | public static void main(String[] args) { 37 | DatagramSocket rtpSock = null; 38 | DatagramSocket rtcpSock = null; 39 | 40 | try { 41 | rtpSock = new DatagramSocket(1233); 42 | rtcpSock = new DatagramSocket(1234); 43 | } catch (Exception e) { 44 | //do nothing 45 | } 46 | RTPSession rtpSession = new RTPSession(rtpSock, rtcpSock); 47 | 48 | System.out.println("************************** SSRC: " + rtpSession.ssrc + " **************************"); 49 | ParticipantDatabase partDb = new ParticipantDatabase(rtpSession); 50 | //InetAddress test = InetAddress.getByName("127.0.0.1"); 51 | Participant part1 = new Participant("127.0.0.1",12, 34); 52 | Participant part2 = new Participant("127.0.0.2",56, 78); 53 | 54 | part1.ssrc = 123; 55 | part2.ssrc = 345; 56 | 57 | InetSocketAddress testadr = null; 58 | 59 | try { 60 | testadr = InetSocketAddress.createUnresolved("localhost", 12371); 61 | } catch (Exception e) { 62 | // Do nothing 63 | } 64 | 65 | part1.cname = "test3"; 66 | part2.cname = "test2"; 67 | part1.loc = "1231231231"; 68 | part2.loc = "Asker"; 69 | part1.phone = "+452 1231231"; 70 | part2.phone = "aasdasda.asdasdas"; 71 | part1.lastSeqNumber = 111; 72 | part2.lastSeqNumber = 222; 73 | part1.timeStampLSR = 111111; 74 | part2.timeStampLSR = 222222; 75 | partDb.addParticipant(0,part1); 76 | partDb.addParticipant(0,part2); 77 | 78 | Participant[] partArray = new Participant[2]; 79 | partArray[0] = part1; 80 | partArray[1] = part2; 81 | 82 | RtcpPktRR rrpkt = new RtcpPktRR(partArray,123456789); 83 | RtcpPktSR srpkt = new RtcpPktSR(rtpSession.ssrc,12,21,rrpkt); 84 | //RtcpPktSR srpkt2 = new RtcpPktSR(rtpSession.ssrc,12,21,null); 85 | //rrpkt = new RtcpPktRR(partArray,1234512311); 86 | 87 | //srpkt.debugPrint(); 88 | //rrpkt.debugPrint(); 89 | 90 | CompRtcpPkt compkt = new CompRtcpPkt(); 91 | compkt.addPacket(srpkt); 92 | compkt.addPacket(rrpkt); 93 | compkt.addPacket(rrpkt); 94 | 95 | byte[] test2 = compkt.encode(); 96 | //System.out.print(StaticProcs.bitsOfBytes(test)); 97 | System.out.println("****************************** DONE ENCODING *******************************"); 98 | CompRtcpPkt decomppkt = new CompRtcpPkt(test2,test2.length,testadr,rtpSession); 99 | System.out.println("****************************** DONE DECODING *******************************"); 100 | System.out.println("Problem code:" + decomppkt.problem); 101 | 102 | ListIterator iter = decomppkt.rtcpPkts.listIterator(); 103 | int i = 0; 104 | 105 | while(iter.hasNext()) { 106 | System.out.println(" i:" + i + " "); 107 | i++; 108 | 109 | Object aPkt = iter.next(); 110 | if( aPkt.getClass() == RtcpPktRR.class) { 111 | RtcpPktRR pkt = (RtcpPktRR) aPkt; 112 | pkt.debugPrint(); 113 | } else if(aPkt.getClass() == RtcpPktSR.class) { 114 | RtcpPktSR pkt = (RtcpPktSR) aPkt; 115 | pkt.debugPrint(); 116 | } 117 | } 118 | 119 | System.out.println("****************************** BYE *******************************"); 120 | long[] tempArray = {rtpSession.ssrc}; 121 | byte[] tempReason = "tas".getBytes(); 122 | RtcpPktBYE byepkt = new RtcpPktBYE(tempArray,tempReason); 123 | //byepkt.debugPrint(); 124 | byepkt.encode(); 125 | byte[] rawpktbye = byepkt.rawPkt; 126 | 127 | RtcpPktBYE byepkt2 = new RtcpPktBYE(rawpktbye,0); 128 | byepkt2.debugPrint(); 129 | 130 | System.out.println("****************************** SDES *******************************"); 131 | RtcpPktSDES sdespkt = new RtcpPktSDES(true,rtpSession,null); 132 | rtpSession.cname = "cname123@localhost"; 133 | //rtpSession.loc = "right here"; 134 | sdespkt.encode(); 135 | //rtpSession.cname = "cname124@localhost"; 136 | //rtpSession.loc = "right hera"; 137 | byte[] rawpktsdes = sdespkt.rawPkt; 138 | InetSocketAddress tmpAdr = (InetSocketAddress) rtpSock.getLocalSocketAddress(); 139 | RtcpPktSDES decsdespkt = new RtcpPktSDES(rawpktsdes, 0, (InetSocketAddress) rtpSock.getLocalSocketAddress() , partDb); 140 | decsdespkt.debugPrint(); 141 | //partDb.debugPrint(); 142 | 143 | CompRtcpPkt compkt2 = new CompRtcpPkt(); 144 | compkt2.addPacket(srpkt); 145 | compkt2.addPacket(sdespkt); 146 | byte[] compkt2Raw = compkt.encode(); 147 | 148 | CompRtcpPkt compkt3 = new CompRtcpPkt(compkt2Raw,compkt2Raw.length,tmpAdr,rtpSession); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RtcpPkt.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.net.InetAddress; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | /** 25 | * Common RTCP packet headers. 26 | * 27 | * @author Arne Kepp 28 | */ 29 | public class RtcpPkt { 30 | /** Logger instance. */ 31 | private static final Logger LOGGER = 32 | Logger.getLogger(RtcpPkt.class.getName()); 33 | 34 | /** Whether a problem has been encountered during parsing */ 35 | protected int problem = 0; 36 | /** The version, always 2, 2 bits */ 37 | protected int version = 2; 38 | /** Padding , 1 bit */ 39 | protected int padding = 0; 40 | /** Number of items, e.g. receiver report blocks. Usage may vary. 5 bits */ 41 | protected int itemCount = 0; 42 | /** The type of RTCP packet, 8 bits */ 43 | protected int packetType = -1; 44 | /** The length of the RTCP packet, in 32 bit blocks minus 1. 16 bits*/ 45 | protected int length = -1; 46 | /** The ssrc that sent this, usually dictated by RTP Session */ 47 | protected long ssrc = -1; 48 | 49 | /** Contains the actual data (eventually) */ 50 | protected byte[] rawPkt = null; 51 | 52 | /** Only used for feedback messages: Time message was generated */ 53 | protected long time = -1; 54 | /** Only used for feedback message: Whether this packet was received */ 55 | protected boolean received = false; 56 | 57 | 58 | /** 59 | * Parses the common header of an RTCP packet 60 | * 61 | * @param start where in this.rawPkt the headers start 62 | * @return true if parsing succeeded and header cheks 63 | */ 64 | protected boolean parseHeaders(int start) { 65 | version = ((rawPkt[start+0] & 0xC0) >>> 6); 66 | padding = ((rawPkt[start+0] & 0x20) >>> 5); 67 | itemCount = (rawPkt[start+0] & 0x1F); 68 | packetType = (int) rawPkt[start+1]; 69 | if(packetType < 0) { 70 | packetType += 256; 71 | } 72 | length = StaticProcs.bytesToUIntInt(rawPkt, start+2); 73 | 74 | if(LOGGER.isLoggable(Level.FINEST)) { 75 | LOGGER.finest(" <-> RtcpPkt.parseHeaders() version:"+version+" padding:"+padding+" itemCount:"+itemCount 76 | +" packetType:"+packetType+" length:"+length); 77 | } 78 | 79 | if(packetType > 207 || packetType < 200) 80 | LOGGER.warning("RtcpPkt.parseHeaders problem discovered, packetType " + packetType); 81 | 82 | if(version == 2 && length < 65536) { 83 | return true; 84 | } else { 85 | LOGGER.warning("RtcpPkt.parseHeaders() failed header checks, check size and version"); 86 | this.problem = -1; 87 | return false; 88 | } 89 | } 90 | /** 91 | * Writes the common header of RTCP packets. 92 | * The values should be filled in when the packet is initiliazed and this function 93 | * called at the very end of .encode() 94 | */ 95 | protected void writeHeaders() { 96 | byte aByte = 0; 97 | aByte |=(version << 6); 98 | aByte |=(padding << 5); 99 | aByte |=(itemCount); 100 | rawPkt[0] = aByte; 101 | aByte = 0; 102 | aByte |= packetType; 103 | rawPkt[1] = aByte; 104 | if(rawPkt.length % 4 != 0) 105 | LOGGER.warning("!!!! RtcpPkt.writeHeaders() rawPkt was not a multiple of 32 bits / 4 octets!"); 106 | byte[] someBytes = StaticProcs.uIntIntToByteWord((rawPkt.length / 4) - 1); 107 | rawPkt[2] = someBytes[0]; 108 | rawPkt[3] = someBytes[1]; 109 | } 110 | 111 | /** 112 | * This is just a dummy to make Eclipse complain less. 113 | */ 114 | protected void encode() { 115 | LOGGER.warning("RtcpPkt.encode() should never be invoked!! " + this.packetType); 116 | } 117 | 118 | /** 119 | * Check whether this packet came from the source we expected. 120 | * 121 | * Not currently used! 122 | * 123 | * @param adr address that packet came from 124 | * @param partDb the participant database for the session 125 | * @return true if this packet came from the expected source 126 | */ 127 | protected boolean check(InetAddress adr, ParticipantDatabase partDb) { 128 | //Multicast -> We have to be naive 129 | if (partDb.rtpSession.mcSession && adr.equals(partDb.rtpSession.mcGroup)) 130 | return true; 131 | 132 | //See whether this participant is known 133 | Participant part = partDb.getParticipant(this.ssrc); 134 | if(part != null && part.rtcpAddress.getAddress().equals(adr)) 135 | return true; 136 | 137 | //If not, we should look for someone without SSRC with his ip-address? 138 | return false; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/demo/SoundReceiverDemo.java: -------------------------------------------------------------------------------- 1 | /* This file is based on 2 | * http://www.anyexample.com/programming/java/java_play_wav_sound_file.xml 3 | * 4 | * Java RTP Library (jlibrtp) 5 | * Copyright (C) 2006 Arne Kepp 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | package org.jlibrtp.demo; 23 | 24 | import java.net.DatagramSocket; 25 | 26 | import javax.sound.sampled.AudioFormat; 27 | import javax.sound.sampled.AudioSystem; 28 | import javax.sound.sampled.DataLine; 29 | import javax.sound.sampled.FloatControl; 30 | import javax.sound.sampled.LineUnavailableException; 31 | import javax.sound.sampled.SourceDataLine; 32 | 33 | import org.jlibrtp.DataFrame; 34 | import org.jlibrtp.Participant; 35 | import org.jlibrtp.RTPAppIntf; 36 | import org.jlibrtp.RTPSession; 37 | 38 | /** 39 | * @author Arne Kepp 40 | */ 41 | public class SoundReceiverDemo implements RTPAppIntf { 42 | //test 43 | RTPSession rtpSession = null; 44 | private Position curPosition; 45 | byte[] abData = null; 46 | int nBytesRead = 0; 47 | int pktCount = 0; 48 | int dataCount = 0; 49 | int offsetCount = 0; 50 | SourceDataLine auline; 51 | 52 | enum Position { 53 | LEFT, RIGHT, NORMAL 54 | }; 55 | 56 | public void receiveData(DataFrame frame, Participant p) { 57 | if(auline != null) { 58 | byte[] data = frame.getConcatenatedData(); 59 | auline.write(data, 0, data.length); 60 | 61 | //dataCount += data.length; 62 | //if(pktCount % 10 == 0) { 63 | // System.out.println("pktCount:" + pktCount + " dataCount:" + dataCount); 64 | // long test = 0; 65 | // for(int i=0; i "); 116 | System.out.println("Assuming 16384 and 16385 for testing purposes"); 117 | 118 | args = new String[2]; 119 | args[0] = new String("16384"); 120 | args[1] = new String("16385"); 121 | } 122 | 123 | 124 | 125 | //SoundReceiverDemo aDemo = new SoundReceiverDemo( 126 | // Integer.getInteger(args[0]), Integer.getInteger(args[1])); 127 | SoundReceiverDemo aDemo = new SoundReceiverDemo( 16384, 16385); 128 | 129 | aDemo.doStuff(); 130 | System.out.println("Done"); 131 | } 132 | 133 | /** 134 | * Demo working method. 135 | */ 136 | public void doStuff() { 137 | System.out.println("-> ReceiverDemo.doStuff()"); 138 | AudioFormat.Encoding encoding = new AudioFormat.Encoding("PCM_SIGNED"); 139 | AudioFormat format = new AudioFormat(encoding,((float) 8000.0), 16, 1, 2, ((float) 8000.0) ,false); 140 | System.out.println(format.toString()); 141 | auline = null; 142 | DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 143 | 144 | try { 145 | auline = (SourceDataLine) AudioSystem.getLine(info); 146 | auline.open(format); 147 | } catch (LineUnavailableException e) { 148 | e.printStackTrace(); 149 | return; 150 | } catch (Exception e) { 151 | e.printStackTrace(); 152 | return; 153 | } 154 | 155 | if (auline.isControlSupported(FloatControl.Type.PAN)) { 156 | FloatControl pan = (FloatControl) auline 157 | .getControl(FloatControl.Type.PAN); 158 | if (this.curPosition == Position.RIGHT) 159 | pan.setValue(1.0f); 160 | else if (this.curPosition == Position.LEFT) 161 | pan.setValue(-1.0f); 162 | } 163 | 164 | auline.start(); 165 | try { 166 | while (nBytesRead != -1) { 167 | // Used to write audio to auline here, 168 | // now moved directly to receiveData. 169 | try { Thread.sleep(1000); } catch(Exception e) { } 170 | } 171 | } finally { 172 | auline.drain(); 173 | auline.close(); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/protocols/rtp/RTPOutputStream.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | package org.jlibrtp.protocols.rtp; 20 | 21 | import java.io.IOException; 22 | import java.io.OutputStream; 23 | import java.util.logging.Level; 24 | import java.util.logging.Logger; 25 | 26 | import org.jlibrtp.RTPSession; 27 | 28 | /** 29 | *

Title: RTPOutputStream

30 | * 31 | *

Description: Output stream that sends the audio in "real time"

32 | * 33 | *

Copyright: Copyright (c) 2008

34 | * 35 | *

Company: www.VoiceInteraction.pt

36 | * 37 | * @author Renato Cassaca 38 | * @version 1.0 39 | */ 40 | public class RTPOutputStream extends OutputStream { 41 | /** Logger instance. */ 42 | private static final Logger LOGGER = 43 | Logger.getLogger(RTPOutputStream.class.getName()); 44 | 45 | //RTPSession 46 | private final RTPSession rtpSession; 47 | 48 | //Number of RTP packets that should be sent per second 49 | private final long packetSize; 50 | 51 | //The time in seconds of each frame contents 52 | private final double packetDuration; 53 | 54 | //Buffer that will store bytes to send 55 | private final CircularByteBuffer circularByteBuffer; 56 | 57 | //The next packet timestamp 58 | private long pktTmestamp; 59 | 60 | //Buffer that hols temporary read data 61 | private final byte[] buffer; 62 | 63 | /** 64 | * Constructor 65 | * Given a RTPSession builds an OutputStream to it 66 | * 67 | * @param rtpSession RTPSession 68 | * @param bytesPerSecond long 69 | * @param packetsPerSecond int 70 | */ 71 | public RTPOutputStream(RTPSession rtpSession, long bytesPerSecond, 72 | int packetsPerSecond) { 73 | this.rtpSession = rtpSession; 74 | 75 | packetSize = bytesPerSecond / packetsPerSecond; 76 | packetDuration = 1000f * ((double) packetSize / (double) bytesPerSecond); 77 | pktTmestamp = -1; 78 | buffer = new byte[(int) packetSize]; 79 | 80 | circularByteBuffer = new CircularByteBuffer(buffer.length); 81 | } 82 | 83 | public void write(int b) throws IOException { 84 | circularByteBuffer.getOutputStream().write(b); 85 | 86 | drain(); 87 | } 88 | 89 | public void write(byte b[], int off, int len) throws IOException { 90 | circularByteBuffer.getOutputStream().write(b, off, len); 91 | 92 | drain(); 93 | } 94 | 95 | private void drain() throws IOException { 96 | while (circularByteBuffer.getInputStream().available() >= packetSize) { 97 | sendData(); 98 | } 99 | } 100 | 101 | public void flush() throws IOException { 102 | drain(); 103 | 104 | //Make sure that buffer is empty 105 | if (circularByteBuffer.getInputStream().available() > 0) { 106 | circularByteBuffer.clear(); 107 | } 108 | 109 | pktTmestamp = -1; 110 | } 111 | 112 | public void close() throws IOException { 113 | if (LOGGER.isLoggable(Level.FINE)) { 114 | LOGGER.fine("RTPOutputStream.close() called"); 115 | } 116 | circularByteBuffer.getOutputStream().close(); 117 | circularByteBuffer.getInputStream().close(); 118 | rtpSession.endSession(); 119 | if (LOGGER.isLoggable(Level.FINE)) { 120 | LOGGER.fine("RTPOutputStream.close() done! (rtpEndSession)"); 121 | } 122 | pktTmestamp = -1; 123 | } 124 | 125 | /** 126 | * Send data to RTP session 127 | * 128 | * @todo Should reset timestamp if current time has long passed 129 | */ 130 | private void sendData() throws IOException { 131 | 132 | //Initialize timestamp 133 | if (pktTmestamp < 0) { 134 | pktTmestamp = (long) (System.nanoTime() * 1E-6); 135 | } 136 | 137 | //Fill buffer to send 138 | int bytesRead = circularByteBuffer.getInputStream().read(buffer); 139 | if (bytesRead != packetSize) { 140 | if (bytesRead < 0) { 141 | //ENDED?? 142 | LOGGER.info("bytesRead != packetSize... @ RTPOutputStream"); 143 | } 144 | } 145 | 146 | //Send data 147 | byte[][] pkt = {buffer}; 148 | rtpSession.sendData(pkt, null, null, pktTmestamp, null); 149 | 150 | //Try to keep send rate as "real time" as possible... 151 | long sleepTime = pktTmestamp - (long) (System.nanoTime() * 1E-6); 152 | while (sleepTime > 0) { 153 | try { 154 | Thread.sleep(0, 999999); 155 | sleepTime--; 156 | } catch (InterruptedException ex) { 157 | if (LOGGER.isLoggable(Level.FINE)) { 158 | LOGGER.fine(ex.getLocalizedMessage()); 159 | } 160 | return; 161 | } 162 | } 163 | 164 | //Update timestamp 165 | pktTmestamp += packetDuration; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RtcpPktRTPFB.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * RTCP packets for RTP Feedback Messages 26 | * 27 | * In line with RFC 4585, this packet currently only supports NACKs 28 | * 29 | * @author Arne Kepp 30 | */ 31 | public class RtcpPktRTPFB extends RtcpPkt { 32 | /** Logger instance. */ 33 | private static final Logger LOGGER = 34 | Logger.getLogger(RtcpPktRTPFB.class.getName()); 35 | 36 | /** If this packet was for a different SSRC */ 37 | protected boolean notRelevant = false; 38 | /** SSRC we are sending feeback to */ 39 | protected long ssrcMediaSource = -1; 40 | /** RTP sequence numbers of lost packets */ 41 | protected int PID[]; 42 | /** bitmask of following lost packets, shared index with PID */ 43 | protected int BLP[]; 44 | 45 | /** 46 | * Constructor for RTP Feedback Message 47 | * 48 | * @param ssrcPacketSender SSRC of sender, taken from RTPSession 49 | * @param ssrcMediaSource SSRC of recipient of this message 50 | * @param FMT the Feedback Message Subtype 51 | * @param PID RTP sequence numbers of lost packets 52 | * @param BLP bitmask of following lost packets, shared index with PID 53 | */ 54 | protected RtcpPktRTPFB(long ssrcPacketSender, long ssrcMediaSource, int FMT, int[] PID, int[] BLP) { 55 | super.packetType = 205; //RTPFB 56 | super.itemCount = FMT; 57 | this.PID = PID; 58 | this.BLP = BLP; 59 | } 60 | 61 | /** 62 | * Constructor that parses a raw packet to retrieve information 63 | * 64 | * @param aRawPkt the raw packet to be parsed 65 | * @param start the start of the packet, in bytes 66 | * @param rtpSession the session on which the callback interface resides 67 | */ 68 | protected RtcpPktRTPFB(byte[] aRawPkt, int start, RTPSession rtpSession) { 69 | if(LOGGER.isLoggable(Level.FINEST)) { 70 | LOGGER.finest(" -> RtcpPktRTPFB(byte[], int start)"); 71 | } 72 | 73 | rawPkt = aRawPkt; 74 | 75 | if(! super.parseHeaders(start) || packetType != 205 || super.length < 2) { 76 | if(LOGGER.isLoggable(Level.FINEST)) { 77 | LOGGER.finest(" <-> RtcpPktRTPFB.parseHeaders() etc. problem"); 78 | } 79 | super.problem = -205; 80 | } else { 81 | //FMT = super.itemCount; 82 | 83 | ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt,8+start); 84 | 85 | if(ssrcMediaSource == rtpSession.ssrc) { 86 | super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt,4+start); 87 | int loopStop = super.length - 2; 88 | PID = new int[loopStop]; 89 | BLP = new int[loopStop]; 90 | int curStart = 12; 91 | 92 | // Loop over Feedback Control Information (FCI) fields 93 | for(int i=0; i< loopStop; i++) { 94 | PID[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart); 95 | BLP[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart + 2); 96 | curStart += 4; 97 | } 98 | 99 | rtpSession.rtcpAVPFIntf.RTPFBPktReceived( 100 | super.ssrc, super.itemCount, PID, BLP); 101 | } 102 | } 103 | 104 | 105 | 106 | if(LOGGER.isLoggable(Level.FINEST)) { 107 | LOGGER.finest(" <- RtcpPktRTPFB()"); 108 | } 109 | } 110 | 111 | /** 112 | * Encode the packet into a byte[], saved in .rawPkt 113 | * 114 | * CompRtcpPkt will call this automatically 115 | */ 116 | protected void encode() { 117 | super.rawPkt = new byte[12 + this.PID.length*4]; 118 | 119 | byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc); 120 | System.arraycopy(someBytes, 0, super.rawPkt, 4, 4); 121 | someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource); 122 | System.arraycopy(someBytes, 0, super.rawPkt, 8, 4); 123 | 124 | // Loop over Feedback Control Information (FCI) fields 125 | int curStart = 12; 126 | for(int i=0; i < this.PID.length; i++ ) { 127 | someBytes = StaticProcs.uIntIntToByteWord(PID[i]); 128 | super.rawPkt[curStart++] = someBytes[0]; 129 | super.rawPkt[curStart++] = someBytes[1]; 130 | someBytes = StaticProcs.uIntIntToByteWord(BLP[i]); 131 | super.rawPkt[curStart++] = someBytes[0]; 132 | super.rawPkt[curStart++] = someBytes[1]; 133 | } 134 | writeHeaders(); 135 | } 136 | 137 | /** 138 | * Get the FMT (Feedback Message Type) 139 | * @return value stored in .itemcount, same field 140 | */ 141 | protected int getFMT() { 142 | return this.itemCount; 143 | } 144 | 145 | /** 146 | * Debug purposes only 147 | */ 148 | protected void debugPrint() { 149 | LOGGER.finest("->RtcpPktRTPFB.debugPrint() "); 150 | LOGGER.finest(" ssrcPacketSender: " + super.ssrc + " ssrcMediaSource: " + ssrcMediaSource); 151 | 152 | if(this.PID != null && this.PID.length < 1) { 153 | LOGGER.finest(" No Feedback Control Information (FCI) fields"); 154 | } 155 | 156 | for(int i=0; i < this.PID.length; i++ ) { 157 | LOGGER.finest(" FCI -> PID: " + PID[i] + " BLP: " + BLP[i]); 158 | } 159 | LOGGER.finest("<-RtcpPktRTPFB.debugPrint() "); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/protocols/rtp/CircularByteBuffer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2009 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp.protocols.rtp; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | 25 | public class CircularByteBuffer { 26 | private int readOfs = 0; 27 | 28 | private int writeOfs = 0; 29 | 30 | private int initialSize; 31 | 32 | private CircularByteBufferInputStream is; 33 | 34 | private CircularByteBufferOutputStream os; 35 | 36 | private byte[] buf; 37 | 38 | public CircularByteBuffer(int initialSize) { 39 | buf = new byte[initialSize]; 40 | this.initialSize = initialSize; 41 | is = new CircularByteBufferInputStream(this); 42 | os = new CircularByteBufferOutputStream(this); 43 | } 44 | 45 | private synchronized int bytesLeft() { 46 | return buf.length - bytesUsed(); 47 | } 48 | 49 | private synchronized int bytesUsed() { 50 | if(readOfs == writeOfs) 51 | return 0; 52 | 53 | if(readOfs < writeOfs) 54 | return writeOfs - readOfs; 55 | 56 | return buf.length - (writeOfs - readOfs); 57 | } 58 | 59 | private void doubleBuf() { 60 | byte[] oldBuf = buf; 61 | buf = new byte[oldBuf.length*2]; 62 | 63 | System.arraycopy(oldBuf, 0, buf, 0, oldBuf.length); 64 | } 65 | 66 | private synchronized void write(byte[] data, int offset, int length) { 67 | while(length > bytesLeft()) { 68 | doubleBuf(); 69 | } 70 | 71 | if(writeOfs + length > buf.length) { 72 | int endLength = buf.length - this.writeOfs; 73 | 74 | System.arraycopy(data, 0, buf, writeOfs, endLength); 75 | 76 | writeOfs = 0; 77 | length = length - endLength; 78 | offset = endLength + offset; 79 | } 80 | 81 | System.arraycopy(data, offset, buf, writeOfs, length); 82 | 83 | writeOfs += length; 84 | } 85 | 86 | private synchronized int read(byte[] buffer, int offset, int length) { 87 | int maxLeft= this.bytesUsed(); 88 | int bytesLeft = length; 89 | 90 | if(maxLeft < bytesLeft) { 91 | bytesLeft = maxLeft; 92 | length = maxLeft; 93 | } 94 | 95 | if(readOfs + length > buf.length) { 96 | int endLength = buf.length - readOfs; 97 | 98 | System.arraycopy(buf, readOfs, buffer, offset, endLength); 99 | 100 | readOfs = 0; 101 | bytesLeft = bytesLeft - endLength; 102 | offset = offset + endLength; 103 | } 104 | 105 | System.arraycopy(buf, readOfs, buffer, offset, bytesLeft); 106 | 107 | readOfs += bytesLeft; 108 | 109 | return length; 110 | } 111 | 112 | public synchronized void clear() { 113 | readOfs = 0; 114 | writeOfs = 0; 115 | buf = new byte[this.initialSize]; 116 | } 117 | 118 | public String debugPrintFunction() { 119 | return this.buf.length + " " + readOfs + " " + writeOfs + " " + this.bytesLeft() + " " + this.bytesUsed(); 120 | } 121 | 122 | public String debugPrintData() { 123 | String str = ""; 124 | for(int i=0; iThis is an example of how to set up a Unicast session.

30 | *

It does not accept any input arguments and is therefore of limited practical value, but it shows 31 | * the basics.

32 | * 33 | *

The class has to implement RTPAppIntf.

34 | * @author Arne Kepp 35 | */ 36 | public class UnicastExample2 implements RTPAppIntf { 37 | /** The tests included in this file */ 38 | static boolean jing = false; 39 | static boolean abhijeet = true; 40 | static long byteCounter = 0; 41 | static long pktCounter = 0; 42 | 43 | /** Holds a RTPSession instance */ 44 | RTPSession rtpSession = null; 45 | 46 | 47 | /** 48 | * A minimal constructor. 49 | * @param rtpSession the RTP session 50 | */ 51 | public UnicastExample2(RTPSession rtpSession) { 52 | this.rtpSession = rtpSession; 53 | } 54 | 55 | // RTPAppIntf All of the following are documented in the JavaDocs 56 | /** 57 | * Used to receive data from the RTP Library. We expect no data. 58 | * {@inheritDoc} 59 | */ 60 | public void receiveData(DataFrame frame, Participant p) { 61 | /** 62 | * This concatenates all received packets for a single timestamp 63 | * into a single byte[] 64 | */ 65 | byte[] data = frame.getConcatenatedData(); 66 | byteCounter += data.length; 67 | pktCounter++; 68 | 69 | if(pktCounter%100 == 0) { 70 | System.out.print("."); 71 | } 72 | 73 | //String cname = p.getCNAME(); 74 | //if(! abhijeet) { 75 | // System.out.println("Received data from " + cname); 76 | // System.out.println(new String(data)); 77 | //} 78 | } 79 | 80 | /** 81 | * Used to communicate updates to the user database through RTCP. 82 | * {@inheritDoc} 83 | */ 84 | public void userEvent(int type, Participant[] participant) { 85 | //Do nothing 86 | } 87 | 88 | /** 89 | * How many packets make up a complete frame for the payload type? 90 | * {@inheritDoc} 91 | */ 92 | public int frameSize(int payloadType) { 93 | return 1; 94 | } 95 | // RTPAppIntf/ 96 | 97 | 98 | /** 99 | * Main method. 100 | * @param args command line parameters 101 | */ 102 | public static void main(String[] args) { 103 | // 1. Create sockets for the RTPSession 104 | DatagramSocket rtpSocket = null; 105 | DatagramSocket rtcpSocket = null; 106 | 107 | if(jing) { 108 | System.out.println("Running test case for Jing"); 109 | } else if(abhijeet) { 110 | System.out.println("Running test case for Abhijeet"); 111 | } else { 112 | System.out.println("Enable one of the test cases in the source code first."); 113 | return; 114 | } 115 | 116 | int portnum = 0; 117 | if(args.length != 1) { 118 | System.out.println("Please specify 1 or 2, denoting the participant."); 119 | return; 120 | } else { 121 | if(args[0].equals("1")) { 122 | portnum = 16384; 123 | } else if(args[0].equals("2")) { 124 | portnum = 16386; 125 | } else { 126 | System.out.println("Unknown argument"); 127 | return; 128 | } 129 | } 130 | System.out.println("Participant "+args[0]+", binding to "+portnum+","+(portnum+1)); 131 | 132 | try { 133 | rtpSocket = new DatagramSocket(portnum); 134 | rtcpSocket = new DatagramSocket(portnum + 1); 135 | } catch (Exception e) { 136 | System.out.println("RTPSession failed to obtain port"); 137 | } 138 | 139 | // 2. Create the RTP session 140 | RTPSession rtpSession = new RTPSession(rtpSocket, rtcpSocket); 141 | //rtpSession.naivePktReception(true); 142 | 143 | System.out.println("My CNAME:" + rtpSession.CNAME()); 144 | 145 | // 3. Instantiate the application object 146 | UnicastExample2 uex = new UnicastExample2(rtpSession); 147 | 148 | // 4. Add participants we want to notify upon registration 149 | // a. Hopefully nobody is listening on this port. 150 | if(portnum == 16386) 151 | portnum = 16382; 152 | 153 | Participant part = new Participant("127.0.0.1", portnum+2, portnum+3); 154 | System.out.println("Will send stuff to "+(portnum+2)+","+(portnum+3)); 155 | rtpSession.addParticipant(part); 156 | 157 | // 5. Register the callback interface, this launches RTCP threads too 158 | // The two null parameters are for the RTCP and debug interfaces, not use here 159 | rtpSession.registerRTPSession(uex, null, null); 160 | 161 | // Wait 2500 ms, because of the initial RTCP wait 162 | try{ Thread.sleep(5000); } catch(Exception e) {} 163 | 164 | // Note: The wait is optional, but insures SDES packets 165 | // receive participants before continuing 166 | 167 | // 6. Send some data 168 | if(args[0].equals("1")) { 169 | System.out.print("Sending data"); 170 | } else { 171 | System.out.print("Receiving data"); 172 | } 173 | if(jing) { 174 | // RTCP SR, RR test for Jing... so we send a little data, and spend a long 175 | // time doing it to collect some reports 176 | byte[] tmp = new byte[10]; 177 | int i; 178 | 179 | for(i=0; i < 60; i++) { 180 | try{ Thread.sleep(200); } catch(Exception e) {} 181 | 182 | if(args[0].equals("1")) 183 | rtpSession.sendData(tmp); 184 | 185 | if(i%10 == 0) 186 | System.out.print("."); 187 | } 188 | 189 | if(args[0].equals("1")) 190 | System.out.println("Done, sent " + (i*10) + " bytes "); 191 | 192 | } else if(abhijeet) { 193 | // Test for abhijeet 194 | 195 | // The question was whether jlibrtp has a problem if you send 4 Mbyte+? 196 | // Could also be related to number of packets, but there are 197 | // current no known bugs in that category either. 198 | 199 | byte[] tmp = new byte[1024]; 200 | int i; 201 | 202 | for(i=0; i < 4000; i++) { 203 | try{ Thread.sleep(5); } catch(Exception e) {} 204 | 205 | if(args[0].equals("1")) { 206 | rtpSession.sendData(tmp); 207 | 208 | if(i%100 == 0) 209 | System.out.print("."); 210 | } 211 | } 212 | 213 | if(args[0].equals("1")) 214 | System.out.println("Done sent, sent " + i + " kbytes "); 215 | } 216 | 217 | // Give the sending threads etc a chance to complete. 218 | try{ Thread.sleep(1000); } catch(Exception e) {} 219 | System.out.println("Received " + byteCounter +" bytes"); 220 | // 7. Terminate the session, takes a few ms to kill threads in order. 221 | rtpSession.endSession(); 222 | //This may result in "Sleep interrupted" messages, ignore them 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RtcpPktSR.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * RTCP packets for Sender Reports 26 | * 27 | * @author Arne Kepp 28 | */ 29 | public class RtcpPktSR extends RtcpPkt { 30 | /** Logger instance. */ 31 | private static final Logger LOGGER = 32 | Logger.getLogger(RtcpPktSR.class.getName()); 33 | 34 | /** NTP timestamp, MSB */ 35 | protected long ntpTs1 = -1; //32 bits 36 | /** NTP timestamp, LSB */ 37 | protected long ntpTs2 = -1; //32 bits 38 | /** RTP timestamp */ 39 | protected long rtpTs = -1; //32 bits 40 | /** Senders packet count */ 41 | protected long sendersPktCount = -1; //32 bits 42 | /** Senders octet count */ 43 | protected long sendersOctCount = -1; //32 bits 44 | /** RR packet with receiver reports that we can append */ 45 | protected RtcpPktRR rReports = null; 46 | 47 | /** 48 | * Constructor for a new Sender Report packet 49 | * 50 | * @param ssrc the senders SSRC, presumably from RTPSession 51 | * @param pktCount packets sent in this session 52 | * @param octCount octets sent in this session 53 | * @param rReports receiver reports, as RR packets, to be included in this packet 54 | */ 55 | protected RtcpPktSR(long ssrc, long pktCount, long octCount, RtcpPktRR rReports) { 56 | // Fetch all the right stuff from the database 57 | super.ssrc = ssrc; 58 | super.packetType = 200; 59 | sendersPktCount = pktCount; 60 | sendersOctCount = octCount; 61 | this.rReports = rReports; 62 | } 63 | 64 | /** 65 | * Constructor that parses a received packet 66 | * 67 | * @param aRawPkt the raw packet 68 | * @param start the position at which SR starts 69 | * @param length used to determine number of included receiver reports 70 | */ 71 | protected RtcpPktSR(byte[] aRawPkt, int start, int length) { 72 | if(LOGGER.isLoggable(Level.FINEST)) { 73 | LOGGER.finest(" -> RtcpPktSR(rawPkt)"); 74 | } 75 | 76 | super.rawPkt = aRawPkt; 77 | 78 | if(!super.parseHeaders(start) || packetType != 200 ) { 79 | if(LOGGER.isLoggable(Level.FINEST)) { 80 | LOGGER.finest(" <-> RtcpPktSR.parseHeaders() etc. problem: "+ (!super.parseHeaders(start) ) + " " + packetType + " " + super.length); 81 | } 82 | super.problem = -200; 83 | } else { 84 | super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt,4+start); 85 | if(length > 11) 86 | ntpTs1 = StaticProcs.bytesToUIntLong(aRawPkt,8+start); 87 | if(length > 15) 88 | ntpTs2 = StaticProcs.bytesToUIntLong(aRawPkt,12+start); 89 | if(length > 19) 90 | rtpTs = StaticProcs.bytesToUIntLong(aRawPkt,16+start); 91 | if(length > 23) 92 | sendersPktCount = StaticProcs.bytesToUIntLong(aRawPkt,20+start); 93 | if(length > 27) 94 | sendersOctCount = StaticProcs.bytesToUIntLong(aRawPkt,24+start); 95 | 96 | // RRs attached? 97 | if(itemCount > 0) { 98 | rReports = new RtcpPktRR(rawPkt,start,itemCount); 99 | } 100 | } 101 | 102 | if(LOGGER.isLoggable(Level.FINEST)) { 103 | LOGGER.finest(" <- RtcpPktSR(rawPkt)"); 104 | } 105 | } 106 | 107 | /** 108 | * Encode the packet into a byte[], saved in .rawPkt 109 | * 110 | * CompRtcpPkt will call this automatically 111 | */ 112 | protected void encode() { 113 | if(LOGGER.isLoggable(Level.FINEST)) { 114 | if(this.rReports != null) { 115 | LOGGER.finest(" -> RtcpPktSR.encode() receptionReports.length: " + this.rReports.length ); 116 | } else { 117 | LOGGER.finest(" -> RtcpPktSR.encode() receptionReports: null"); 118 | } 119 | } 120 | 121 | if(this.rReports != null) { 122 | super.itemCount = this.rReports.reportees.length; 123 | 124 | byte[] tmp = this.rReports.encodeRR(); 125 | super.rawPkt = new byte[tmp.length+28]; 126 | //super.length = (super.rawPkt.length / 4) - 1; 127 | 128 | System.arraycopy(tmp, 0, super.rawPkt, 28, tmp.length); 129 | 130 | } else { 131 | super.itemCount = 0; 132 | super.rawPkt = new byte[28]; 133 | //super.length = 6; 134 | } 135 | //Write the common header 136 | super.writeHeaders(); 137 | 138 | // Convert to NTP and chop up 139 | long timeNow = System.currentTimeMillis(); 140 | ntpTs1 = 2208988800L + (timeNow/1000); 141 | long ms = timeNow % 1000; 142 | double tmp = ((double)ms) / 1000.0; 143 | tmp = tmp * (double)4294967295L; 144 | ntpTs2 = (long) tmp; 145 | rtpTs = System.currentTimeMillis(); 146 | 147 | //Write SR stuff 148 | byte[] someBytes; 149 | someBytes = StaticProcs.uIntLongToByteWord(super.ssrc); 150 | System.arraycopy(someBytes, 0, super.rawPkt, 4, 4); 151 | someBytes = StaticProcs.uIntLongToByteWord(ntpTs1); 152 | System.arraycopy(someBytes, 0, super.rawPkt, 8, 4); 153 | someBytes = StaticProcs.uIntLongToByteWord(ntpTs2); 154 | System.arraycopy(someBytes, 0, super.rawPkt, 12, 4); 155 | someBytes = StaticProcs.uIntLongToByteWord(rtpTs); 156 | System.arraycopy(someBytes, 0, super.rawPkt, 16, 4); 157 | someBytes = StaticProcs.uIntLongToByteWord(sendersPktCount); 158 | System.arraycopy(someBytes, 0, super.rawPkt, 20, 4); 159 | someBytes = StaticProcs.uIntLongToByteWord(sendersOctCount); 160 | System.arraycopy(someBytes, 0, super.rawPkt, 24, 4); 161 | 162 | if(LOGGER.isLoggable(Level.FINEST)) { 163 | LOGGER.finest(" <- RtcpPktSR.encode() ntpTs1: " 164 | + Long.toString(ntpTs1) + " ntpTs2: " + Long.toString(ntpTs2)); 165 | } 166 | } 167 | 168 | /** 169 | * Debug purposes only 170 | */ 171 | public void debugPrint() { 172 | LOGGER.finest("RtcpPktSR.debugPrint() "); 173 | LOGGER.finest(" SSRC:"+Long.toString(super.ssrc) +" ntpTs1:"+Long.toString(ntpTs1) 174 | +" ntpTS2:"+Long.toString(ntpTs2)+" rtpTS:"+Long.toString(rtpTs) 175 | +" senderPktCount:"+Long.toString(sendersPktCount)+" sendersOctetCount:" 176 | +Long.toString(sendersOctCount)); 177 | if(this.rReports != null) { 178 | System.out.print(" Part of Sender Report: "); 179 | this.rReports.debugPrint(); 180 | LOGGER.finest(" End Sender Report"); 181 | } else { 182 | LOGGER.finest("No Receiver Reports associated with this Sender Report."); 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/RTPReceiverThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.io.IOException; 22 | import java.net.DatagramPacket; 23 | import java.net.InetSocketAddress; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | 27 | /** 28 | * The RTP receiver thread waits on the designated UDP socket for new packets. 29 | * 30 | * Once one arrives, it is parsed and tested. We also check the ip-address of the sender. 31 | * If accepted, the packet is added onto the packet buffer of the participant. 32 | * 33 | * A separate thread moves the packet from the packet buffer to the application. 34 | * 35 | * @author Arne Kepp 36 | */ 37 | public class RTPReceiverThread extends Thread { 38 | /** Logger instance. */ 39 | private static final Logger LOGGER = 40 | Logger.getLogger(RTPReceiverThread.class.getName()); 41 | 42 | /** Parent RTP Session */ 43 | private RTPSession rtpSession = null; 44 | 45 | /** 46 | * Constructs a new object. 47 | * @param session the session 48 | */ 49 | public RTPReceiverThread(RTPSession session) { 50 | rtpSession = session; 51 | if(LOGGER.isLoggable(Level.FINEST)) { 52 | LOGGER.finest("<-> RTPReceiverThread created"); 53 | } 54 | setName("RTPReceiverThread"); 55 | } 56 | 57 | /** 58 | * Working method. 59 | */ 60 | public void run() { 61 | if(LOGGER.isLoggable(Level.FINEST)) { 62 | if(rtpSession.mcSession) { 63 | LOGGER.finest("-> RTPReceiverThread.run() starting on MC " + rtpSession.rtpMCSock.getLocalPort() ); 64 | } else { 65 | LOGGER.finest("-> RTPReceiverThread.run() starting on " + rtpSession.rtpSock.getLocalPort() ); 66 | } 67 | } 68 | 69 | while(!rtpSession.endSession) { 70 | if(LOGGER.isLoggable(Level.FINEST)) { 71 | if(rtpSession.mcSession) { 72 | LOGGER.finest("-> RTPReceiverThread.run() waiting for MC packet on " + rtpSession.rtpMCSock.getLocalPort() ); 73 | } else { 74 | LOGGER.finest("-> RTPReceiverThread.run() waiting for packet on " + rtpSession.rtpSock.getLocalPort() ); 75 | } 76 | } 77 | 78 | // Prepare a packet 79 | byte[] rawPkt = new byte[1500]; 80 | DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length); 81 | // Wait for it to arrive 82 | if(! rtpSession.mcSession) { 83 | //Unicast 84 | try { 85 | rtpSession.rtpSock.receive(packet); 86 | } catch (IOException e) { 87 | if(!rtpSession.endSession) { 88 | e.printStackTrace(); 89 | } else { 90 | continue; 91 | } 92 | } 93 | } else { 94 | //Multicast 95 | try { 96 | rtpSession.rtpMCSock.receive(packet); 97 | } catch (IOException e) { 98 | if(!rtpSession.endSession) { 99 | e.printStackTrace(); 100 | } else { 101 | continue; 102 | } 103 | } 104 | } 105 | 106 | // Parse the received RTP (?) packet 107 | RtpPkt pkt = new RtpPkt(rawPkt, packet.getLength()); 108 | if(pkt.getVersion() != 2) { 109 | // Some old phones, like the SNOM 190, are transmitting one 110 | // Version=0 RTP packet before sending Version=2 RTP packets. 111 | System.out.println("Received invalid RTP packet. Ignoring"); 112 | continue; 113 | } 114 | long pktSsrc = pkt.getSsrc(); 115 | 116 | // Check for loops and SSRC collisions 117 | if( rtpSession.ssrc == pktSsrc ) 118 | rtpSession.resolveSsrcConflict(); 119 | 120 | long[] csrcArray = pkt.getCsrcArray(); 121 | if( csrcArray != null) { 122 | for(int i=0; i< csrcArray.length; i++) { 123 | if(csrcArray[i] == rtpSession.ssrc) { 124 | rtpSession.resolveSsrcConflict(); 125 | } 126 | } 127 | } 128 | 129 | if(LOGGER.isLoggable(Level.FINEST)) { 130 | LOGGER.finest("-> RTPReceiverThread.run() rcvd packet, seqNum " + rtpSession.seqNum + ", ssrc " + pktSsrc); 131 | String str = new String(pkt.getPayload()); 132 | LOGGER.finest("-> RTPReceiverThread.run() payload is " + str ); 133 | } 134 | 135 | //Find the participant in the database based on SSRC 136 | Participant part = rtpSession.partDb.getParticipant(pktSsrc); 137 | 138 | if(part == null) { 139 | InetSocketAddress nullSocket = null; 140 | part = new Participant((InetSocketAddress) packet.getSocketAddress(), nullSocket, pkt.getSsrc()); 141 | part.unexpected = true; 142 | rtpSession.partDb.addParticipant(1, part); 143 | // Note: when adding participant, the result may be an updated pre-existing participant that lacked 144 | // a ssrc. Thus, we need to find the participant that is really stored in the partDb after adding. 145 | // Otherwise the packet will be added to a participant not connected to a rtpSession. 146 | part = rtpSession.partDb.getParticipant(pktSsrc); 147 | } 148 | 149 | // Do checks on whether the datagram came from the expected source for that SSRC. 150 | if(part.rtpAddress == null || packet.getAddress().equals(part.rtpAddress.getAddress())) { 151 | PktBuffer pktBuffer = part.pktBuffer; 152 | 153 | if(pktBuffer != null) { 154 | //A buffer already exists, append to it 155 | pktBuffer.addPkt(pkt); 156 | } else { 157 | // Create a new packet/frame buffer 158 | pktBuffer = new PktBuffer(this.rtpSession, part,pkt); 159 | part.pktBuffer = pktBuffer; 160 | } 161 | } else { 162 | LOGGER.warning("RTPReceiverThread: Got an unexpected packet from " + pkt.getSsrc() 163 | + " the sending ip-address was " + packet.getAddress().toString() 164 | + ", we expected from " + part.rtpAddress.toString()); 165 | } 166 | 167 | // Statistics for receiver report. 168 | part.updateRRStats(packet.getLength(), pkt); 169 | // Upate liveness 170 | part.lastRtpPkt = System.currentTimeMillis(); 171 | 172 | if(LOGGER.isLoggable(Level.FINEST)) { 173 | LOGGER.finest("<-> RTPReceiverThread signalling pktBufDataReady"); 174 | } 175 | 176 | // Signal the thread that pushes data to application 177 | rtpSession.pktBufLock.lock(); 178 | try { rtpSession.pktBufDataReady.signalAll(); } finally { 179 | rtpSession.pktBufLock.unlock(); 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /org.jlibrtp.demo/src/main/java/org/jlibrtp/demo/XmlPacketPlayer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | package org.jlibrtp.demo; 21 | 22 | import java.io.File; 23 | import java.net.DatagramSocket; 24 | import java.util.Iterator; 25 | import java.util.List; 26 | 27 | import org.jdom2.Document; 28 | import org.jdom2.Element; 29 | import org.jdom2.input.SAXBuilder; 30 | import org.jlibrtp.DataFrame; 31 | import org.jlibrtp.Participant; 32 | import org.jlibrtp.RTPAppIntf; 33 | import org.jlibrtp.RTPSession; 34 | import org.jlibrtp.StaticProcs; 35 | 36 | /** 37 | * XML Packet player demo. 38 | * @author Arne Kepp 39 | * 40 | */ 41 | public class XmlPacketPlayer implements RTPAppIntf { 42 | private RTPSession rtpSession = null; 43 | private Document document = null; 44 | private long origStartTime = -1; 45 | private long startTime = -1; 46 | private int dataCount = 0; 47 | private int pktCount = 0; 48 | 49 | /** 50 | * Constructs a new object. 51 | * @param rtpPortNum RTP port number 52 | * @param rtcpPortNum RTCP port number 53 | * @param address address to use 54 | */ 55 | public XmlPacketPlayer(int rtpPortNum, int rtcpPortNum, String address) { 56 | DatagramSocket rtpSocket = null; 57 | DatagramSocket rtcpSocket = null; 58 | 59 | try { 60 | rtpSocket = new DatagramSocket(rtpPortNum+2); 61 | rtcpSocket = new DatagramSocket(rtcpPortNum+2); 62 | } catch (Exception e) { 63 | System.out.println(e.getMessage()); 64 | System.out.println("RTPSession failed to obtain port"); 65 | } 66 | 67 | this.rtpSession = new RTPSession(rtpSocket, rtcpSocket); 68 | Participant p = new Participant(address, rtpPortNum, rtcpPortNum); 69 | this.rtpSession.addParticipant(p); 70 | 71 | System.out.println("Done creating player."); 72 | } 73 | 74 | /** 75 | * Parses the file with the given name. 76 | * @param filename file to parse 77 | */ 78 | public void parseDocument(String filename) { 79 | System.out.println("Parsing document " + filename); 80 | try { 81 | SAXBuilder builder = new SAXBuilder(); 82 | this.document = builder.build(new File(filename)); 83 | } catch(Exception e) { 84 | e.printStackTrace(); 85 | } 86 | 87 | //RTPSession 88 | Element elm = document.getRootElement(); 89 | List children = elm.getChildren(); 90 | 91 | Iterator iter = children.iterator(); 92 | 93 | //sessionInformation 94 | elm = iter.next(); 95 | 96 | parseSessionInfo(elm); 97 | 98 | //this.rtpSession.RTPSessionRegister(this,null,null); 99 | 100 | // RTP and RTCP packets 101 | while(iter.hasNext()) { 102 | elm = (Element) iter.next(); 103 | if(elm.getName().equals("RTPpacket")) { 104 | parseRTPpacket(elm); 105 | } else { 106 | //System.out.println("ah..." + elm.getName()); 107 | } 108 | } 109 | 110 | } 111 | 112 | /** 113 | * Parses the session info from the element. 114 | * @param elm the element to pars 115 | */ 116 | public void parseSessionInfo(Element elm) { 117 | System.out.println("Parsing Session Information"); 118 | 119 | List children = elm.getChildren(); 120 | Iterator iter = children.iterator(); 121 | 122 | int i = 0; 123 | while(i < 3 && iter.hasNext()) { 124 | elm = iter.next(); 125 | if(elm.getName().equals("SSRC")) { 126 | //Ignore 127 | } else if(elm.getName().equals("CNAME")) { 128 | this.rtpSession.CNAME(elm.getValue()); 129 | } else if(elm.getName().equals("sessionStart")) { 130 | this.origStartTime = Long.parseLong(elm.getValue()); 131 | } 132 | i++; 133 | } 134 | this.startTime = System.currentTimeMillis(); 135 | } 136 | 137 | /** 138 | * Parses the RTP packet from the provided element. 139 | * @param elm the element to parse 140 | */ 141 | public void parseRTPpacket(Element elm) { 142 | //System.out.println("Parsing RTP packet"); 143 | 144 | long ssrc = -1; 145 | long targetTime = -1; 146 | long rtpTimestamp = -1; 147 | int seqNum = -1; 148 | int payloadType = -1; 149 | byte[] buf = null; 150 | 151 | List children = elm.getChildren(); 152 | Iterator iter = children.iterator(); 153 | 154 | while(iter.hasNext()) { 155 | elm = iter.next(); 156 | if(elm.getName().equals("SSRC")) { 157 | ssrc = Long.parseLong(elm.getValue()); 158 | 159 | } else if(elm.getName().equals("ArrivalTimestamp")) { 160 | targetTime = Long.parseLong(elm.getValue()); 161 | 162 | } else if(elm.getName().equals("RTPTimestamp")) { 163 | rtpTimestamp = Long.parseLong(elm.getValue()); 164 | 165 | } else if(elm.getName().equals("SequenceNumber")) { 166 | seqNum = Integer.parseInt(elm.getValue()); 167 | 168 | } else if(elm.getName().equals("PayloadType")) { 169 | payloadType = Integer.parseInt(elm.getValue()); 170 | 171 | } else if(elm.getName().equals("Payload")) { 172 | byte[] bytes = elm.getValue().getBytes(); 173 | byte[] tmp = new byte[2]; 174 | buf = new byte[bytes.length/2]; 175 | int ipos = 0; 176 | int jpos = 0; 177 | while(ipos < bytes.length) { 178 | tmp[0] = bytes[ipos++]; 179 | tmp[1] = bytes[ipos++]; 180 | buf[jpos++] = StaticProcs.byteOfHex(tmp); 181 | } 182 | } 183 | } 184 | rtpSession.payloadType(payloadType); 185 | preSendSleep(targetTime); 186 | rtpSession.sendData(buf); 187 | 188 | //dataCount += buf.length; 189 | //if(pktCount % 10 == 0) { 190 | // System.out.println("pktCount:" + pktCount + " dataCount:" + dataCount); 191 | // 192 | // long test = 0; 193 | // for(int i=0; i curDiff) { 213 | sleepTime = origDiff - curDiff; 214 | } 215 | 216 | //System.out.println("Sleeping for " + sleepTime); 217 | 218 | try { 219 | Thread.sleep(sleepTime); 220 | } catch (InterruptedException e) { } 221 | } 222 | 223 | /** 224 | * {@inheritDoc} 225 | */ 226 | public void receiveData(DataFrame frame, Participant participant) { 227 | //dummy; 228 | } 229 | /** 230 | * {@inheritDoc} 231 | */ 232 | public void userEvent(int type, Participant[] participant) { 233 | //dummy 234 | } 235 | /** 236 | * {@inheritDoc} 237 | */ 238 | public int frameSize(int payloadType) { 239 | //dummy 240 | return 1; 241 | } 242 | 243 | 244 | /** 245 | * Main method. 246 | * @param args command line arguments 247 | */ 248 | public static void main(String[] args) { 249 | int rtpPortNum = -1; 250 | int rtcpPortNum = -1; 251 | String hostname = ""; 252 | String filename = ""; 253 | 254 | boolean run = false; 255 | if (args.length == 4) { 256 | try { 257 | hostname = args[0]; 258 | rtpPortNum = Integer.parseInt(args[1]); 259 | rtcpPortNum = Integer.parseInt(args[2]); 260 | filename = args[3]; 261 | } catch (NumberFormatException e) { 262 | System.out.println(e.getMessage()); 263 | } 264 | run = true; 265 | } else if(args.length == 0) { 266 | System.out.println("Syntax: "); 267 | System.out.println("java XmlPacketPlayer "); 268 | System.out.println(""); 269 | System.out.println("Using default values for testing, will only work on a UNIX clone:"); 270 | System.out.println("java XmlPacketPlayer 127.0.0.1 16384 16385 /home/ak/jlibrtp_packets.xml"); 271 | hostname = "127.0.0.1"; 272 | rtpPortNum = 16384; 273 | rtcpPortNum = 16385; 274 | filename = "test.xml"; 275 | run = true; 276 | } else { 277 | System.out.println("Syntax: "); 278 | System.out.println("java XmlPacketPlayer "); 279 | } 280 | 281 | if(run) { 282 | XmlPacketPlayer player = new XmlPacketPlayer(rtpPortNum, rtcpPortNum, hostname); 283 | player.parseDocument(filename); 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/StaticProcs.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Logger; 22 | 23 | /** 24 | * Generic functions for converting between unsigned integers and byte[]s. 25 | * 26 | * @author Arne Kepp 27 | */ 28 | public class StaticProcs { 29 | /** Logger instance. */ 30 | private static final Logger LOGGER = 31 | Logger.getLogger(RTPReceiverThread.class.getName()); 32 | 33 | /** 34 | * Converts an integer into an array of bytes. 35 | * Primarily used for 16 bit unsigned integers, ignore the first two octets. 36 | * 37 | * @param i a 16 bit unsigned integer in an int 38 | * @return byte[2] representing the integer as unsigned, most significant bit first. 39 | */ 40 | public static byte[] uIntIntToByteWord(int i) { 41 | byte[] byteWord = new byte[2]; 42 | byteWord[0] = (byte) ((i >> 8) & 0x000000FF); 43 | byteWord[1] = (byte) (i & 0x00FF); 44 | return byteWord; 45 | } 46 | 47 | /** 48 | * Converts an unsigned 32 bit integer, stored in a long, into an array of bytes. 49 | * 50 | * @param j a long 51 | * @return byte[4] representing the unsigned integer, most significant bit first. 52 | */ 53 | public static byte[] uIntLongToByteWord(long j) { 54 | int i = (int) j; 55 | byte[] byteWord = new byte[4]; 56 | byteWord[0] = (byte) ((i >>> 24) & 0x000000FF); 57 | byteWord[1] = (byte) ((i >> 16) & 0x000000FF); 58 | byteWord[2] = (byte) ((i >> 8) & 0x000000FF); 59 | byteWord[3] = (byte) (i & 0x00FF); 60 | return byteWord; 61 | } 62 | 63 | /** 64 | * Combines two bytes (most significant bit first) into a 16 bit unsigned integer. 65 | * 66 | * @param index of most significant byte 67 | * @return int with the 16 bit unsigned integer 68 | */ 69 | public static int bytesToUIntInt(byte[] bytes, int index) { 70 | int accum = 0; 71 | int i = 1; 72 | for (int shiftBy = 0; shiftBy < 16; shiftBy += 8 ) { 73 | accum |= ( (long)( bytes[index + i] & 0xff ) ) << shiftBy; 74 | i--; 75 | } 76 | return accum; 77 | } 78 | 79 | /** 80 | * Combines four bytes (most significant bit first) into a 32 bit unsigned integer. 81 | * 82 | * @param bytes bytes to convert 83 | * @param index of most significant byte 84 | * @return long with the 32 bit unsigned integer 85 | */ 86 | public static long bytesToUIntLong(byte[] bytes, int index) { 87 | long accum = 0; 88 | int i = 3; 89 | for (int shiftBy = 0; shiftBy < 32; shiftBy += 8 ) { 90 | accum |= ( (long)( bytes[index + i] & 0xff ) ) << shiftBy; 91 | i--; 92 | } 93 | return accum; 94 | } 95 | 96 | /** 97 | * Converts an arbitrary number of bytes, assumed to represent an unsigned integer, 98 | * to a Java long 99 | */ 100 | /*public static long bytesToUintLong(byte[] bytes, int firstByte, int lastByte) { 101 | long accum = 0; 102 | int i = lastByte - firstByte; 103 | if(i > 7) { 104 | System.out.println("!!!! StaticProcs.bytesToUintLong() Can't convert more than 63 bits!"); 105 | return -1; 106 | } 107 | int stop = (i+1)*8; 108 | 109 | for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { 110 | accum |= ( (long)( bytes[firstByte + i] & 0xff ) ) << shiftBy; 111 | i--; 112 | } 113 | return accum; 114 | }*/ 115 | 116 | /** 117 | * Converts an arbitrary number of bytes, assumed to represent an unsigned integer, 118 | * to a Java int 119 | */ 120 | /* public static int bytesToUintInt(byte[] bytes, int firstByte, int lastByte) { 121 | int accum = 0; 122 | int i = lastByte - firstByte; 123 | if(i > 3) { 124 | System.out.println("!!!! StaticProcs.bytesToUintLong() Can't convert more than 31 bits!"); 125 | return -1; 126 | } 127 | int stop = (i+1)*8; 128 | 129 | for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { 130 | accum |= ( (long)( bytes[firstByte + i] & 0xff ) ) << shiftBy; 131 | i--; 132 | } 133 | return accum; 134 | }*/ 135 | 136 | /** 137 | * Recreates a UNIX timestamp based on the NTP representation used 138 | * in RTCP SR packets 139 | * 140 | * @param ntpTs1 from RTCP SR packet 141 | * @param ntpTs2 from RTCP SR packet 142 | * @return the UNIX timestamp 143 | */ 144 | public static long undoNtpMess(long ntpTs1, long ntpTs2) { 145 | long timeVal = (ntpTs1 - 2208988800L)*1000; 146 | 147 | double tmp = (1000.0*(double)ntpTs2)/((double)4294967295L); 148 | long ms = (long) tmp; 149 | //System.out.println(" timeVal: " +Long.toString(timeVal)+ " ms " + Long.toString(ms)); 150 | timeVal += ms; 151 | 152 | return timeVal; 153 | } 154 | 155 | 156 | 157 | /** 158 | * Get the bits of a byte 159 | * 160 | * @param aByte the byte you wish to convert 161 | * @return a String of 1's and 0's 162 | */ 163 | public static String bitsOfByte(byte aByte) { 164 | int temp; 165 | String out = ""; 166 | for(int i=7; i>=0; i--) { 167 | temp = (aByte >>> i); 168 | temp &= 0x0001; 169 | out += (""+temp); 170 | } 171 | return out; 172 | } 173 | 174 | /** 175 | * Get the hex representation of a byte 176 | * 177 | * @param aByte the byte you wish to convert 178 | * @return a String of two chars 0-1,A-F 179 | */ 180 | public static String hexOfByte(byte aByte) { 181 | String out = ""; 182 | 183 | for(int i=0; i<2; i++) { 184 | int temp = (int) aByte; 185 | if(temp < 0) { 186 | temp +=256; 187 | } 188 | if(i == 0) { 189 | temp = temp/16; 190 | } else { 191 | temp = temp%16; 192 | } 193 | 194 | if( temp > 9) { 195 | switch(temp) { 196 | case 10: out += "A"; break; 197 | case 11: out += "B"; break; 198 | case 12: out += "C"; break; 199 | case 13: out += "D"; break; 200 | case 14: out += "E"; break; 201 | case 15: out += "F"; break; 202 | } 203 | } else { 204 | out += Integer.toString(temp); 205 | } 206 | } 207 | return out; 208 | } 209 | 210 | /** 211 | * Get the hex representation of a byte 212 | * 213 | * @param hex 4 bytes the byte you wish to convert 214 | * @return a String of two chars 0-1,A-F 215 | */ 216 | public static byte byteOfHex(byte[] hex) { 217 | byte retByte = 0; 218 | Byte tmp; 219 | int val = 0; 220 | 221 | // First 4 bits 222 | tmp = hex[0]; 223 | val = tmp.intValue(); 224 | if(val > 64) { 225 | // Letter 226 | val -= 55; 227 | } else { 228 | // Number 229 | val -= 48; 230 | } 231 | retByte = ((byte) (val << 4)); 232 | 233 | // Last 4 bits 234 | tmp = hex[1]; 235 | val = tmp.intValue(); 236 | if(val > 64) { 237 | // Letter 238 | val -= 55; 239 | } else { 240 | // Number 241 | val -= 48; 242 | } 243 | retByte |= ((byte) val); 244 | 245 | return retByte; 246 | } 247 | 248 | 249 | /** 250 | * Print the bits of a byte to standard out. For debugging. 251 | * 252 | * @param aByte the byte you wish to print out. 253 | */ 254 | public static void printBits(byte aByte) { 255 | StringBuffer str = new StringBuffer(); 256 | int temp; 257 | for(int i=7; i>=0; i--) { 258 | temp = (aByte >>> i); 259 | temp &= 0x0001; 260 | str.append(temp); 261 | } 262 | LOGGER.finest(str.toString()); 263 | } 264 | 265 | public static String bitsOfBytes(byte[] bytes) { 266 | String str = ""; 267 | //Expensive, but who cares 268 | for(int i=0; i RtcpPktRR.parseHeaders() etc. problem: "+(!super.parseHeaders(start))+" "+packetType+" "+super.length); 81 | } 82 | super.problem = -201; 83 | } 84 | 85 | int base; 86 | if(rrCount > 0) { 87 | base = start + 28; 88 | } else { 89 | base = start + 8; 90 | rrCount = super.itemCount; 91 | super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, start + 4); 92 | } 93 | 94 | if(rrCount > 0) { 95 | reporteeSsrc = new long[rrCount]; 96 | lossFraction = new int[rrCount]; 97 | lostPktCount = new int[rrCount]; 98 | extHighSeqRecv = new long[rrCount]; 99 | interArvJitter = new long[rrCount]; 100 | timeStampLSR = new long[rrCount]; 101 | delaySR = new long[rrCount]; 102 | 103 | for(int i=0; i RtcpPktRR.encode()"); 125 | } 126 | 127 | byte[] rRs = null; 128 | //Gather up the actual receiver reports 129 | if(this.reportees != null) { 130 | rRs = this.encodeRR(); 131 | super.rawPkt = new byte[rRs.length + 8]; 132 | System.arraycopy(rRs, 0, super.rawPkt, 8, rRs.length); 133 | super.itemCount = reportees.length; 134 | } else { 135 | super.rawPkt = new byte[8]; 136 | super.itemCount = 0; 137 | } 138 | 139 | //Write the common header 140 | super.writeHeaders(); 141 | 142 | //Add our SSRC (as sender) 143 | byte[] someBytes; 144 | someBytes = StaticProcs.uIntLongToByteWord(super.ssrc); 145 | System.arraycopy(someBytes, 0, super.rawPkt, 4, 4); 146 | 147 | if(LOGGER.isLoggable(Level.FINEST)) { 148 | LOGGER.finest(" <- RtcpPktRR.encode()"); 149 | } 150 | 151 | } 152 | 153 | /** 154 | * Encodes the individual Receiver Report blocks, 155 | * 156 | * so they can be used either in RR packets or appended to SR 157 | * 158 | * @return the encoded packets 159 | */ 160 | protected byte[] encodeRR() { 161 | if(LOGGER.isLoggable(Level.FINEST)) { 162 | LOGGER.finest(" -> RtcpPktRR.encodeRR()"); 163 | } 164 | //assuming we will always create complete reports: 165 | byte[] ret = new byte[24*reportees.length]; 166 | 167 | //Write SR stuff 168 | for(int i = 0; i= 0) { 187 | someBytes = StaticProcs.uIntLongToByteWord((long)reportees[i].interArrivalJitter); 188 | } else { 189 | someBytes = StaticProcs.uIntLongToByteWord((long) 0); 190 | } 191 | System.arraycopy(someBytes, 0, ret, 12 + offset, 4); 192 | 193 | // Timestamp last sender report received 194 | someBytes = StaticProcs.uIntLongToByteWord(reportees[i].timeStampLSR); 195 | System.arraycopy(someBytes, 0, ret, 16 + offset, 4); 196 | 197 | // Delay since last sender report received, in terms of 1/655536 s = 0.02 ms 198 | if(reportees[i].timeReceivedLSR > 0) { 199 | someBytes = StaticProcs.uIntLongToByteWord(reportees[i].delaySinceLastSR()); 200 | } else { 201 | someBytes = StaticProcs.uIntLongToByteWord(0); 202 | } 203 | System.arraycopy(someBytes, 0, ret, 20 + offset, 4); 204 | } 205 | if(LOGGER.isLoggable(Level.FINEST)) { 206 | LOGGER.finest(" <- RtcpPktRR.encodeRR()"); 207 | } 208 | return ret; 209 | } 210 | 211 | /** 212 | * Debug purposes only 213 | */ 214 | public void debugPrint() { 215 | LOGGER.finest("RtcpPktRR.debugPrint() "); 216 | if(reportees != null) { 217 | for(int i= 0; i Run()"); 131 | } 132 | File soundFile = new File(filename); 133 | if (!soundFile.exists()) { 134 | System.err.println("Wave file not found: " + filename); 135 | return; 136 | } 137 | 138 | AudioInputStream audioInputStream = null; 139 | try { 140 | audioInputStream = AudioSystem.getAudioInputStream(soundFile); 141 | } catch (UnsupportedAudioFileException e1) { 142 | e1.printStackTrace(); 143 | return; 144 | } catch (IOException e1) { 145 | e1.printStackTrace(); 146 | return; 147 | } 148 | 149 | //AudioFormat format = audioInputStream.getFormat(); 150 | AudioFormat.Encoding encoding = new AudioFormat.Encoding("PCM_SIGNED"); 151 | AudioFormat format = new AudioFormat(encoding,((float) 8000.0), 16, 1, 2, ((float) 8000.0) ,false); 152 | System.out.println(format.toString()); 153 | 154 | 155 | if(! this.local) { 156 | // To time the output correctly, we also play at the input: 157 | auline = null; 158 | DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 159 | 160 | try { 161 | auline = (SourceDataLine) AudioSystem.getLine(info); 162 | auline.open(format); 163 | } catch (LineUnavailableException e) { 164 | e.printStackTrace(); 165 | return; 166 | } catch (Exception e) { 167 | e.printStackTrace(); 168 | return; 169 | } 170 | 171 | if (auline.isControlSupported(FloatControl.Type.PAN)) { 172 | FloatControl pan = (FloatControl) auline 173 | .getControl(FloatControl.Type.PAN); 174 | if (this.curPosition == Position.RIGHT) 175 | pan.setValue(1.0f); 176 | else if (this.curPosition == Position.LEFT) 177 | pan.setValue(-1.0f); 178 | } 179 | 180 | auline.start(); 181 | } 182 | 183 | int nBytesRead = 0; 184 | byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 185 | long start = System.currentTimeMillis(); 186 | try { 187 | while (nBytesRead != -1 && pktCount < 200) { 188 | nBytesRead = audioInputStream.read(abData, 0, abData.length); 189 | 190 | if (nBytesRead >= 0) { 191 | rtpSession.sendData(abData); 192 | //if(!this.local) { 193 | auline.write(abData, 0, abData.length); 194 | 195 | //dataCount += abData.length; 196 | 197 | //if(pktCount % 10 == 0) { 198 | // System.out.println("pktCount:" + pktCount + " dataCount:" + dataCount); 199 | // 200 | // long test = 0; 201 | // for(int i=0; i iter = this.rtpSession.getParticipants(); 215 | //System.out.println("iter " + iter.hasMoreElements()); 216 | Participant p = null; 217 | 218 | while(iter.hasMoreElements()) { 219 | p = iter.nextElement(); 220 | 221 | String name = "name"; 222 | byte[] nameBytes = name.getBytes(); 223 | String data= "abcd"; 224 | byte[] dataBytes = data.getBytes(); 225 | 226 | 227 | int ret = rtpSession.sendRTCPAppPacket(p.getSSRC(), 0, nameBytes, dataBytes); 228 | System.out.println("!!!!!!!!!!!! ADDED APPLICATION SPECIFIC " + ret); 229 | continue; 230 | } 231 | if(p == null) 232 | System.out.println("No participant with SSRC available :("); 233 | } 234 | } 235 | } catch (IOException e) { 236 | e.printStackTrace(); 237 | return; 238 | } 239 | System.out.println("Time: " + (System.currentTimeMillis() - start)/1000 + " s"); 240 | 241 | try { Thread.sleep(200);} catch(Exception e) {} 242 | 243 | this.rtpSession.endSession(); 244 | 245 | try { Thread.sleep(2000);} catch(Exception e) {} 246 | if(LOGGER.isLoggable(Level.FINER)) { 247 | LOGGER.finer("<- Run()"); 248 | } 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/CompRtcpPkt.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | import java.util.LinkedList; 21 | import java.util.ListIterator; 22 | import java.util.logging.Level; 23 | import java.util.logging.Logger; 24 | import java.net.InetSocketAddress; 25 | 26 | /** 27 | * Compound RTCP packet class. 28 | * 29 | * It basically holds a list of packets. This list can either be constructed 30 | * by providing a byte[] of a compound packet, or by adding individual packets. 31 | * 32 | * Upon encode(), the packet will call encode on all the added packets. 33 | * 34 | * problem == 0 indicates the parsing succeeded. 35 | * 36 | * 37 | * @author Arne Kepp 38 | */ 39 | 40 | public class CompRtcpPkt { 41 | /** Logger instance. */ 42 | private static final Logger LOGGER = 43 | Logger.getLogger(CompRtcpPkt.class.getName()); 44 | 45 | /** Problem indicator, negative values denote packet type that cause problem */ 46 | protected int problem = 0; 47 | /** Stores the different subclasses of RtcpPkt that make up the compound packet */ 48 | protected LinkedList rtcpPkts = new LinkedList(); 49 | 50 | /** 51 | * Instantiates an empty Compound RTCP packet to which you can add RTCP packets 52 | */ 53 | protected CompRtcpPkt() { 54 | // Will have to add packets directly to rtcpPkts. 55 | if(LOGGER.isLoggable(Level.FINE)) { 56 | LOGGER.fine("<-> CompRtcpPkt()"); 57 | } 58 | } 59 | 60 | /** 61 | * Add a RTCP packet to the compound packet. Packets are added in order, 62 | * so you have to ensure that a Sender Report or Receiver Report is 63 | * added first. 64 | * 65 | * @param aPkt the packet to be added 66 | */ 67 | protected void addPacket(RtcpPkt aPkt) { 68 | if(LOGGER.isLoggable(Level.FINE)) { 69 | LOGGER.fine(" <-> CompRtcpPkt.addPacket( "+ aPkt.getClass() + " )"); 70 | } 71 | 72 | if(aPkt.problem == 0) { 73 | rtcpPkts.add(aPkt); 74 | } else { 75 | this.problem = aPkt.problem; 76 | } 77 | } 78 | 79 | /** 80 | * Picks a received Compound RTCP packet apart. 81 | * 82 | * Only SDES packets are processed directly, other packets are 83 | * parsed and put into aComptRtcpPkt.rtcpPkts, but not 84 | * 85 | * Check the aComptRtcpPkt.problem , if the value is non-zero 86 | * the packets should probably be discarded. 87 | * 88 | * @param rawPkt the byte array received from the socket 89 | * @param packetSize the actual number of used bytes 90 | * @param adr the socket address from which the packet was received 91 | * @param rtpSession the RTPSession with the participant database 92 | */ 93 | protected CompRtcpPkt(byte[] rawPkt, int packetSize, InetSocketAddress adr, RTPSession rtpSession) { 94 | if(LOGGER.isLoggable(Level.FINE)) { 95 | LOGGER.fine("-> CompRtcpPkt(" + rawPkt.getClass() + ", size " + packetSize + ", from " + adr.toString() + ", " + rtpSession.getClass() + ")"); 96 | } 97 | //System.out.println("rawPkt.length:" + rawPkt.length + " packetSize:" + packetSize); 98 | 99 | // Chop it up 100 | int start = 0; 101 | 102 | while(start < packetSize && problem == 0) { 103 | int length = (StaticProcs.bytesToUIntInt(rawPkt, start + 2)) + 1; 104 | 105 | if(length*4 + start > rawPkt.length) { 106 | LOGGER.warning("!!!! CompRtcpPkt.(rawPkt,..,..) length ("+ (length*4+start) 107 | + ") exceeds size of raw packet ("+rawPkt.length+") !"); 108 | this.problem = -3; 109 | } 110 | 111 | int pktType = (int) rawPkt[start + 1]; 112 | 113 | if(pktType < 0) { 114 | pktType += 256; 115 | } 116 | 117 | 118 | if(start == 0) { 119 | // Compound packets need to start with SR or RR 120 | if(pktType != 200 && pktType != 201 ) { 121 | LOGGER.info("!!!! CompRtcpPkt(rawPkt...) packet did not start with SR or RR"); 122 | this.problem = -1; 123 | } 124 | 125 | // Padding bit should be zero for the first packet 126 | if(((rawPkt[start] & 0x20) >>> 5) == 1) { 127 | LOGGER.info("!!!! CompRtcpPkt(rawPkt...) first packet was padded"); 128 | this.problem = -2; 129 | } 130 | } 131 | 132 | //System.out.println("start: " + start + " pktType: " + pktType + " length:" + length ); 133 | if(pktType == 200) { 134 | addPacket(new RtcpPktSR(rawPkt,start,length*4)); 135 | } else if(pktType == 201 ) { 136 | addPacket(new RtcpPktRR(rawPkt,start, -1)); 137 | } else if(pktType == 202) { 138 | addPacket(new RtcpPktSDES(rawPkt,start, adr, rtpSession.partDb)); 139 | } else if(pktType == 203 ) { 140 | addPacket(new RtcpPktBYE(rawPkt,start)); 141 | } else if(pktType == 204) { 142 | addPacket(new RtcpPktAPP(rawPkt,start)); 143 | } else if(pktType == 205) { 144 | addPacket(new RtcpPktRTPFB(rawPkt,start, rtpSession)); 145 | } else if(pktType == 206) { 146 | addPacket(new RtcpPktPSFB(rawPkt,start,rtpSession)); 147 | } else { 148 | LOGGER.warning("!!!! CompRtcpPkt(byte[] rawPkt, int packetSize...) " 149 | +"UNKNOWN RTCP PACKET TYPE:" + pktType); 150 | } 151 | 152 | //System.out.println(" start:" + start + " pktType:" + pktType + " length:" + length); 153 | 154 | start += length*4; 155 | 156 | if(LOGGER.isLoggable(Level.FINER)) { 157 | LOGGER.finer(" start:"+start+" parsing pktType "+pktType+" length: "+length); 158 | } 159 | } 160 | if(LOGGER.isLoggable(Level.FINE)) { 161 | LOGGER.fine("<- CompRtcpPkt(rawPkt....)"); 162 | } 163 | } 164 | 165 | /** 166 | * Encode combines the RTCP packets in this.rtcpPkts into a byte[] 167 | * by calling the encode() function on each of them individually. 168 | * 169 | * The order of rtcpPkts is preserved, so a RR or SR packet must be first. 170 | * 171 | * @return the trimmed byte[] representation of the packet, ready to go into a UDP packet. 172 | */ 173 | protected byte[] encode() { 174 | if(LOGGER.isLoggable(Level.FINER)) { 175 | LOGGER.finer(" <- CompRtcpPkt.encode()"); 176 | } 177 | 178 | ListIterator iter = rtcpPkts.listIterator(); 179 | 180 | byte[] rawPkt = new byte[1500]; 181 | int index = 0; 182 | 183 | while(iter.hasNext()) { 184 | RtcpPkt aPkt = (RtcpPkt) iter.next(); 185 | 186 | if(aPkt.packetType == 200) { 187 | RtcpPktSR pkt = (RtcpPktSR) aPkt; 188 | pkt.encode(); 189 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 190 | index += pkt.rawPkt.length; 191 | } else if(aPkt.packetType == 201 ) { 192 | RtcpPktRR pkt = (RtcpPktRR) aPkt; 193 | pkt.encode(); 194 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 195 | index += pkt.rawPkt.length; 196 | } else if(aPkt.packetType == 202) { 197 | RtcpPktSDES pkt = (RtcpPktSDES) aPkt; 198 | pkt.encode(); 199 | //System.out.println(" ENCODE SIZE: " + pkt.rawPkt.length); 200 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 201 | index += pkt.rawPkt.length; 202 | } else if(aPkt.packetType == 203) { 203 | RtcpPktBYE pkt = (RtcpPktBYE) aPkt; 204 | pkt.encode(); 205 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 206 | index += pkt.rawPkt.length; 207 | } else if(aPkt.packetType == 204) { 208 | RtcpPktAPP pkt = (RtcpPktAPP) aPkt; 209 | pkt.encode(); 210 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 211 | index += pkt.rawPkt.length; 212 | } else if(aPkt.packetType == 205) { 213 | RtcpPktRTPFB pkt = (RtcpPktRTPFB) aPkt; 214 | pkt.encode(); 215 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 216 | index += pkt.rawPkt.length; 217 | } else if(aPkt.packetType == 206) { 218 | RtcpPktPSFB pkt = (RtcpPktPSFB) aPkt; 219 | pkt.encode(); 220 | System.arraycopy(pkt.rawPkt, 0, rawPkt, index, pkt.rawPkt.length); 221 | index += pkt.rawPkt.length; 222 | } else { 223 | LOGGER.warning("CompRtcpPkt aPkt.packetType:" + aPkt.packetType); 224 | } 225 | //System.out.println(" packetType:" + aPkt.packetType + " length:" + aPkt.rawPkt.length + " index:" + index); 226 | } 227 | 228 | byte[] output = new byte[index]; 229 | 230 | System.arraycopy(rawPkt, 0, output, 0, index); 231 | 232 | if(LOGGER.isLoggable(Level.FINER)) { 233 | LOGGER.finer(" -> CompRtcpPkt.encode()"); 234 | } 235 | return output; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/DataFrame.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | 25 | /** 26 | * Data structure to hold a complete frame if frame reconstruction 27 | * is enabled, or the data from an individual packet if it is not 28 | * 29 | * It also contains most of the data from the individual packets 30 | * that it is based on. 31 | * 32 | * @author Arne Kepp 33 | */ 34 | public class DataFrame { 35 | /** Logger instance. */ 36 | private static final Logger LOGGER = 37 | Logger.getLogger(DataFrame.class.getName()); 38 | 39 | /** The share RTP timestamp */ 40 | private long rtpTimestamp; 41 | /** The calculated UNIX timestamp, guessed after 2 Sender Reports */ 42 | private long timestamp = -1; 43 | /** the SSRC from which this frame originated */ 44 | private long SSRC; 45 | /** contributing CSRCs, only read from the first packet */ 46 | private long[] CSRCs; 47 | /** RTP payload type */ 48 | private int payloadType; 49 | /** The marks on individual packets, ordered */ 50 | private boolean[] marks; 51 | /** Whether any packets were marked or not */ 52 | private boolean anyMarked = false; 53 | /** Whether the frame contains the expected number of packets */ 54 | private int isComplete = 0; 55 | //private int dataLength; 56 | /** The data from the individual packets, ordered */ 57 | private byte[][] data; 58 | /** The sequence numbers of the individual packets, ordered */ 59 | private int[] seqNum; 60 | /** The total amount of data bytes in this frame */ 61 | private int totalLength = 0; 62 | /** The last sequence number in this frame */ 63 | protected int lastSeqNum; 64 | /** The first sequence number in this frame */ 65 | protected int firstSeqNum; 66 | /** The number of packets expected for a complete frame */ 67 | protected int noPkts; 68 | 69 | /** 70 | * The usual way to construct a frame is by giving it a PktBufNode, 71 | * which contains links to all the other pkts that make it up. 72 | * @param aBufNode node 73 | * @param p the participant 74 | * @param noPkts number of packets 75 | */ 76 | protected DataFrame(PktBufNode aBufNode, Participant p, int noPkts) { 77 | if(LOGGER.isLoggable(Level.FINE)) { 78 | LOGGER.finest("-> DataFrame(PktBufNode, noPkts = " + noPkts +")"); 79 | } 80 | this.noPkts = noPkts; 81 | RtpPkt aPkt = aBufNode.pkt; 82 | int pktCount = aBufNode.pktCount; 83 | firstSeqNum = aBufNode.pktCount; 84 | 85 | // All this data should be shared, so we just get it from the first one 86 | this.rtpTimestamp = aBufNode.timeStamp; 87 | SSRC = aPkt.getSsrc(); 88 | CSRCs = aPkt.getCsrcArray(); 89 | payloadType = aPkt.getPayloadType(); 90 | 91 | // Check whether we can compute an NTPish timestamp? Requires two SR reports 92 | if(p.ntpGradient > 0) { 93 | //System.out.print(Long.toString(p.ntpOffset)+" " 94 | timestamp = p.ntpOffset + (long) (p.ntpGradient*(double)(this.rtpTimestamp-p.lastSRRtpTs)); 95 | } 96 | 97 | // Make data the right length 98 | int payloadLength = aPkt.getPayloadLength(); 99 | //System.out.println("aBufNode.pktCount " + aBufNode.pktCount); 100 | data = new byte[aBufNode.pktCount][payloadLength]; 101 | seqNum = new int[aBufNode.pktCount]; 102 | marks = new boolean[aBufNode.pktCount]; 103 | 104 | // Concatenate the data of the packets 105 | int i; 106 | for(i=0; i< pktCount; i++) { 107 | aPkt = aBufNode.pkt; 108 | byte[] temp = aPkt.getPayload(); 109 | totalLength += temp.length; 110 | if(temp.length == payloadLength) { 111 | data[i] = temp; 112 | } else if(temp.length < payloadLength){ 113 | System.arraycopy(temp, 0, data[i], 0, temp.length); 114 | } else { 115 | LOGGER.info("DataFrame() received node structure with increasing packet payload size."); 116 | } 117 | //System.out.println("i " + i + " seqNum[i] " + seqNum[i] + " aBufNode" + aBufNode); 118 | seqNum[i] = aBufNode.seqNum; 119 | marks[i] = aBufNode.pkt.isMarked(); 120 | if(marks[i]) 121 | anyMarked = true; 122 | 123 | // Get next node 124 | aBufNode = aBufNode.nextFrameNode; 125 | } 126 | 127 | lastSeqNum = seqNum[i - 1]; 128 | 129 | if(noPkts > 0) { 130 | int seqDiff = firstSeqNum - lastSeqNum; 131 | if(seqDiff < 0) 132 | seqDiff = (Integer.MAX_VALUE - firstSeqNum) + lastSeqNum; 133 | if(seqDiff == pktCount && pktCount == noPkts) 134 | isComplete = 1; 135 | } else { 136 | isComplete = -1; 137 | } 138 | 139 | if(LOGGER.isLoggable(Level.FINEST)) { 140 | LOGGER.finest("<- DataFrame(PktBufNode, noPkt), data length: " + data.length); 141 | } 142 | } 143 | 144 | /** 145 | * Returns a two dimensial array where the first dimension represents individual 146 | * packets, from which the frame is made up, in order of increasing sequence number. 147 | * These indeces can be matched to the sequence numbers returned by sequenceNumbers(). 148 | * 149 | * @return 2-dim array with raw data from packets 150 | */ 151 | public byte[][] getData() { 152 | return this.data; 153 | } 154 | 155 | /** 156 | * Returns a concatenated version of the data from getData() 157 | * It ignores missing sequence numbers, but then isComplete() 158 | * will return false provided that RTPAppIntf.frameSize() 159 | * provides a non-negative number for this payload type. 160 | * 161 | * @return byte[] with all the data concatenated 162 | */ 163 | public byte[] getConcatenatedData() { 164 | if(this.noPkts < 2) { 165 | byte[] ret = new byte[this.totalLength]; 166 | int pos = 0; 167 | 168 | for(int i=0; i totalLength) 173 | length = totalLength - pos; 174 | 175 | System.arraycopy(data[i], 0, ret, pos, length); 176 | pos += data[i].length; 177 | } 178 | return ret; 179 | } else { 180 | return data[0]; 181 | } 182 | } 183 | 184 | /** 185 | * If two SR packet have been received jlibrtp will attempt to calculate 186 | * the local UNIX timestamp (in milliseconds) of all packets received. 187 | * 188 | * This value should ideally correspond to the local time when the 189 | * SSRC sent the packet. Note that the source may not be reliable. 190 | * 191 | * Returns -1 if less than two SRs have been received 192 | * 193 | * @return the UNIX timestamp, similar to System.currentTimeMillis() or -1; 194 | */ 195 | public long timestamp() { 196 | return this.timestamp; 197 | 198 | } 199 | 200 | /** 201 | * Returns the RTP timestamp of all the packets in the frame. 202 | * 203 | * @return unmodified RTP timestamp 204 | */ 205 | public long rtpTimestamp() { 206 | return this.rtpTimestamp; 207 | } 208 | 209 | /** 210 | * Returns the payload type of the packets 211 | * 212 | * @return the payload type of the packets 213 | */ 214 | public int payloadType() { 215 | return this.payloadType; 216 | } 217 | 218 | /** 219 | * Returns an array whose values, for the same index, correpond to the 220 | * sequence number of the packet from which the data came. 221 | * 222 | * This information can be valuable in conjunction with getData(), 223 | * to identify what parts of a frame are missing. 224 | * 225 | * @return array with sequence numbers 226 | */ 227 | public int[] sequenceNumbers() { 228 | return seqNum; 229 | } 230 | 231 | /** 232 | * Returns an array whose values, for the same index, correpond to 233 | * whether the data was marked or not. 234 | * 235 | * This information can be valuable in conjunction with getData(). 236 | * 237 | * @return array of booleans 238 | */ 239 | public boolean[] marks() { 240 | return this.marks; 241 | } 242 | 243 | /** 244 | * Returns true if any packet in the frame was marked. 245 | * 246 | * This function should be used if all your frames fit 247 | * into single packets. 248 | * 249 | * @return true if any packet was marked, false otherwise 250 | */ 251 | public boolean marked() { 252 | return this.anyMarked; 253 | } 254 | 255 | /** 256 | * The SSRC associated with this frame. 257 | * 258 | * @return the ssrc that created this frame 259 | */ 260 | public long ssrc() { 261 | return this.SSRC; 262 | } 263 | 264 | /** 265 | * The SSRCs that contributed to this frame 266 | * 267 | * @return an array of contributing SSRCs, or null 268 | */ 269 | public long[] csrcs() { 270 | return this.CSRCs; 271 | } 272 | 273 | /** 274 | * Checks whether the difference in sequence numbers corresponds 275 | * to the number of packets received for the current timestamp, 276 | * and whether this value corresponds to the expected number of 277 | * packets. 278 | * 279 | * @return true if the right number of packets make up the frame 280 | */ 281 | public int complete() { 282 | return this.isComplete; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /org.jlibrtp/src/main/java/org/jlibrtp/ParticipantDatabase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Java RTP Library (jlibrtp) 3 | * Copyright (C) 2006 Arne Kepp 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | package org.jlibrtp; 20 | 21 | import java.util.*; 22 | import java.util.concurrent.*; 23 | import java.util.logging.Logger; 24 | 25 | /** 26 | * The participant database maintains three hashtables with participants. 27 | * 28 | * The key issue is to be fast for operations that happen every time an 29 | * RTP packet is sent or received. We allow linear searching in cases 30 | * where we need to update participants with information. 31 | * 32 | * The keying is therefore usually the SSRC. In cases where we have the 33 | * cname, but no SSRC is known (no SDES packet has been received), a 34 | * simple hash i calculated based on the CNAME. The RTCP code should, 35 | * when receiving SDES packets, check whether the participant is known 36 | * and update the copy in this database with SSRC if needed. 37 | * 38 | * @author Arne Kepp 39 | */ 40 | public class ParticipantDatabase { 41 | /** Logger instance. */ 42 | private static final Logger LOGGER = 43 | Logger.getLogger(ParticipantDatabase.class.getName()); 44 | 45 | /** The parent RTP Session */ 46 | RTPSession rtpSession = null; 47 | /** 48 | * A copy on write list to hold participants explicitly added by the application 49 | * In unicast mode this is the list used for RTP and RTCP transmission, 50 | * in multicast it should not be in use. 51 | */ 52 | CopyOnWriteArrayList receivers = new CopyOnWriteArrayList(); 53 | /** 54 | * The hashtable holds participants added through received RTP and RTCP packets, 55 | * as well as participants that have been linked to an SSRC by ip address (in unicast mode). 56 | */ 57 | ConcurrentHashMap ssrcTable = new ConcurrentHashMap(); 58 | 59 | /** 60 | * Simple constructor 61 | * 62 | * @param parent parent RTPSession 63 | */ 64 | protected ParticipantDatabase(RTPSession parent) { 65 | rtpSession = parent; 66 | } 67 | 68 | /** 69 | * 70 | * @param cameFrom 0: Application, 1: RTP packet, 2: RTCP 71 | * @param p the participant 72 | * @return 0 if okay, -1 if not 73 | */ 74 | protected int addParticipant(int cameFrom, Participant p) { 75 | //Multicast or not? 76 | if(this.rtpSession.mcSession) { 77 | return this.addParticipantMulticast(cameFrom, p); 78 | } else { 79 | return this.addParticipantUnicast(cameFrom, p); 80 | } 81 | 82 | } 83 | 84 | /** 85 | * Add a multicast participant to the database 86 | * 87 | * @param cameFrom 0: Application, 1,2: discovered through RTP or RTCP 88 | * @param p the participant to add 89 | * @return 0 if okay, -2 if redundant, -1 if adding participant to multicast 90 | */ 91 | private int addParticipantMulticast(int cameFrom, Participant p) { 92 | if( cameFrom == 0) { 93 | LOGGER.warning("ParticipantDatabase.addParticipant() doesnt expect" 94 | + " application to add participants to multicast session."); 95 | return -1; 96 | } else { 97 | // Check this one is not redundant 98 | if(this.ssrcTable.contains(p.ssrc)) { 99 | LOGGER.info("ParticipantDatabase.addParticipant() SSRC " 100 | +"already known " + Long.toString(p.ssrc)); 101 | return -2; 102 | } else { 103 | this.ssrcTable.put(p.ssrc, p); 104 | return 0; 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * Add a unicast participant to the database 111 | * 112 | * Result will be reported back through tpSession.appIntf.userEvent 113 | * 114 | * @param cameFrom 0: Application, 1,2: discovered through RTP or RTCP 115 | * @param p the participant to add 116 | * @return 0 if new, 1 if 117 | */ 118 | private int addParticipantUnicast(int cameFrom, Participant p) { 119 | if(cameFrom == 0) { 120 | //Check whether there is a match in the ssrcTable 121 | boolean notDone = true; 122 | 123 | Enumeration enu = this.ssrcTable.elements(); 124 | while(notDone && enu.hasMoreElements()) { 125 | Participant part = enu.nextElement(); 126 | if(part.unexpected && 127 | ((part.rtcpReceivedFromAddress!=null && part.rtcpAddress!=null && part.rtcpReceivedFromAddress.equals(part.rtcpAddress.getAddress())) || 128 | ( part.rtpReceivedFromAddress!=null && part.rtpAddress!=null && part.rtpReceivedFromAddress.equals(part.rtpAddress.getAddress())))) { 129 | 130 | part.rtpAddress = p.rtpAddress; 131 | part.rtcpAddress = p.rtcpAddress; 132 | part.unexpected = false; 133 | 134 | //Report the match back to the application 135 | Participant[] partArray = {part}; 136 | this.rtpSession.appIntf.userEvent(5, partArray); 137 | 138 | notDone = false; 139 | p = part; 140 | } 141 | } 142 | 143 | //Add to the table of people that we send packets to 144 | this.receivers.add(p); 145 | return 0; 146 | 147 | } else { 148 | //Check whether there's a match in the receivers table 149 | boolean notDone = true; 150 | //System.out.println("GOT " + p.cname); 151 | Iterator iter = this.receivers.iterator(); 152 | 153 | while(notDone && iter.hasNext()) { 154 | Participant part = iter.next(); 155 | 156 | //System.out.println(part.rtpAddress.getAddress().toString() 157 | // + " " + part.rtcpAddress.getAddress().toString() 158 | // + " " + p.rtpReceivedFromAddress.getAddress().toString() 159 | // + " " + p.rtcpReceivedFromAddress.getAddress().toString()); 160 | 161 | //System.out.println(" HUUHHHH? " + p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress())); 162 | if((cameFrom == 1 && p.rtpReceivedFromAddress.getAddress().equals(part.rtpAddress.getAddress())) 163 | || (cameFrom == 2 && p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress()))) { 164 | 165 | part.rtpReceivedFromAddress = p.rtpReceivedFromAddress; 166 | part.rtcpReceivedFromAddress = p.rtcpReceivedFromAddress; 167 | 168 | // Move information 169 | part.ssrc = p.ssrc; 170 | part.cname = p.cname; 171 | part.name = p.name; 172 | part.loc = p.loc; 173 | part.phone = p.phone; 174 | part.email = p.email; 175 | part.note = p.note; 176 | part.tool = p.tool; 177 | part.priv = p.priv; 178 | 179 | this.ssrcTable.put(part.ssrc, part); 180 | 181 | //Report the match back to the application 182 | Participant[] partArray = {part}; 183 | this.rtpSession.appIntf.userEvent(5, partArray); 184 | return 0; 185 | } 186 | } 187 | 188 | // No match? ok 189 | this.ssrcTable.put(p.ssrc, p); 190 | return 0; 191 | } 192 | } 193 | 194 | /** 195 | * Remove a participant from all tables 196 | * 197 | * @param p the participant to be removed 198 | */ 199 | protected void removeParticipant(Participant p) { 200 | if(! this.rtpSession.mcSession) 201 | this.receivers.remove(p); 202 | 203 | this.ssrcTable.remove(p.ssrc, p); 204 | } 205 | 206 | /** 207 | * Find a participant based on the ssrc 208 | * 209 | * @param ssrc of the participant to be found 210 | * @return the participant, null if unknonw 211 | */ 212 | protected Participant getParticipant(long ssrc) { 213 | Participant p = null; 214 | p = ssrcTable.get(ssrc); 215 | return p; 216 | } 217 | 218 | /** 219 | * Iterator for all the unicast receivers. 220 | * 221 | * This one is used by both RTP for sending packets, as well as RTCP. 222 | * 223 | * @return iterator for unicast participants 224 | */ 225 | protected Iterator getUnicastReceivers() { 226 | if(! this.rtpSession.mcSession) { 227 | return this.receivers.iterator(); 228 | } else { 229 | LOGGER.warning("Request for ParticipantDatabase.getUnicastReceivers in multicast session"); 230 | return null; 231 | } 232 | } 233 | 234 | /** 235 | * Enumeration of all the participants with known ssrcs. 236 | * 237 | * This is primarily used for sending packets in multicast sessions. 238 | * 239 | * @return enumerator with all the participants with known SSRCs 240 | */ 241 | protected Enumeration getParticipants() { 242 | return this.ssrcTable.elements(); 243 | } 244 | 245 | /** 246 | * Debug dump. 247 | */ 248 | protected void debugPrint() { 249 | LOGGER.finest(" ParticipantDatabase.debugPrint()"); 250 | Participant p; 251 | Enumeration enu = ssrcTable.elements(); 252 | while(enu.hasMoreElements()) { 253 | p = enu.nextElement(); 254 | LOGGER.finest(" ssrcTable ssrc:"+p.ssrc+" cname:"+p.cname 255 | +" loc:"+p.loc+" rtpAddress:"+p.rtpAddress+" rtcpAddress:"+p.rtcpAddress); 256 | } 257 | 258 | Iterator iter = receivers.iterator(); 259 | while(iter.hasNext()) { 260 | p = iter.next(); 261 | LOGGER.finest(" receivers: "+p.rtpAddress.toString()); 262 | } 263 | } 264 | } 265 | --------------------------------------------------------------------------------