1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.rtp;
18 
19 import java.net.InetAddress;
20 import java.net.Inet4Address;
21 import java.net.Inet6Address;
22 import java.net.SocketException;
23 
24 /**
25  * RtpStream represents the base class of streams which send and receive network
26  * packets with media payloads over Real-time Transport Protocol (RTP).
27  *
28  * <p class="note">Using this class requires
29  * {@link android.Manifest.permission#INTERNET} permission.</p>
30  */
31 public class RtpStream {
32     /**
33      * This mode indicates that the stream sends and receives packets at the
34      * same time. This is the initial mode for new streams.
35      */
36     public static final int MODE_NORMAL = 0;
37 
38     /**
39      * This mode indicates that the stream only sends packets.
40      */
41     public static final int MODE_SEND_ONLY = 1;
42 
43     /**
44      * This mode indicates that the stream only receives packets.
45      */
46     public static final int MODE_RECEIVE_ONLY = 2;
47 
48     private static final int MODE_LAST = 2;
49 
50     private final InetAddress mLocalAddress;
51     private final int mLocalPort;
52 
53     private InetAddress mRemoteAddress;
54     private int mRemotePort = -1;
55     private int mMode = MODE_NORMAL;
56 
57     private int mSocket = -1;
58     static {
59         System.loadLibrary("rtp_jni");
60     }
61 
62     /**
63      * Creates a RtpStream on the given local address. Note that the local
64      * port is assigned automatically to conform with RFC 3550.
65      *
66      * @param address The network address of the local host to bind to.
67      * @throws SocketException if the address cannot be bound or a problem
68      *     occurs during binding.
69      */
RtpStream(InetAddress address)70     RtpStream(InetAddress address) throws SocketException {
71         mLocalPort = create(address.getHostAddress());
72         mLocalAddress = address;
73     }
74 
create(String address)75     private native int create(String address) throws SocketException;
76 
77     /**
78      * Returns the network address of the local host.
79      */
getLocalAddress()80     public InetAddress getLocalAddress() {
81         return mLocalAddress;
82     }
83 
84     /**
85      * Returns the network port of the local host.
86      */
getLocalPort()87     public int getLocalPort() {
88         return mLocalPort;
89     }
90 
91     /**
92      * Returns the network address of the remote host or {@code null} if the
93      * stream is not associated.
94      */
getRemoteAddress()95     public InetAddress getRemoteAddress() {
96         return mRemoteAddress;
97     }
98 
99     /**
100      * Returns the network port of the remote host or {@code -1} if the stream
101      * is not associated.
102      */
getRemotePort()103     public int getRemotePort() {
104         return mRemotePort;
105     }
106 
107     /**
108      * Returns {@code true} if the stream is busy. In this case most of the
109      * setter methods are disabled. This method is intended to be overridden
110      * by subclasses.
111      */
isBusy()112     public boolean isBusy() {
113         return false;
114     }
115 
116     /**
117      * Returns the current mode.
118      */
getMode()119     public int getMode() {
120         return mMode;
121     }
122 
123     /**
124      * Changes the current mode. It must be one of {@link #MODE_NORMAL},
125      * {@link #MODE_SEND_ONLY}, and {@link #MODE_RECEIVE_ONLY}.
126      *
127      * @param mode The mode to change to.
128      * @throws IllegalArgumentException if the mode is invalid.
129      * @throws IllegalStateException if the stream is busy.
130      * @see #isBusy()
131      */
setMode(int mode)132     public void setMode(int mode) {
133         if (isBusy()) {
134             throw new IllegalStateException("Busy");
135         }
136         if (mode < 0 || mode > MODE_LAST) {
137             throw new IllegalArgumentException("Invalid mode");
138         }
139         mMode = mode;
140     }
141 
142     /**
143      * Associates with a remote host. This defines the destination of the
144      * outgoing packets.
145      *
146      * @param address The network address of the remote host.
147      * @param port The network port of the remote host.
148      * @throws IllegalArgumentException if the address is not supported or the
149      *     port is invalid.
150      * @throws IllegalStateException if the stream is busy.
151      * @see #isBusy()
152      */
associate(InetAddress address, int port)153     public void associate(InetAddress address, int port) {
154         if (isBusy()) {
155             throw new IllegalStateException("Busy");
156         }
157         if (!(address instanceof Inet4Address && mLocalAddress instanceof Inet4Address) &&
158                 !(address instanceof Inet6Address && mLocalAddress instanceof Inet6Address)) {
159             throw new IllegalArgumentException("Unsupported address");
160         }
161         if (port < 0 || port > 65535) {
162             throw new IllegalArgumentException("Invalid port");
163         }
164         mRemoteAddress = address;
165         mRemotePort = port;
166     }
167 
getSocket()168     int getSocket() {
169         return mSocket;
170     }
171 
172     /**
173      * Releases allocated resources. The stream becomes inoperable after calling
174      * this method.
175      *
176      * @throws IllegalStateException if the stream is busy.
177      * @see #isBusy()
178      */
release()179     public void release() {
180         synchronized (this) {
181             if (isBusy()) {
182                 throw new IllegalStateException("Busy");
183             }
184             close();
185         }
186     }
187 
close()188     private native void close();
189 
190     @Override
finalize()191     protected void finalize() throws Throwable {
192         close();
193         super.finalize();
194     }
195 }
196