• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.HashMap;
20 import java.util.Map;
21 
22 /**
23  * An AudioGroup acts as a router connected to the speaker, the microphone, and
24  * {@link AudioStream}s. Its pipeline has four steps. First, for each
25  * AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its incoming
26  * packets and stores in its buffer. Then, if the microphone is enabled,
27  * processes the recorded audio and stores in its buffer. Third, if the speaker
28  * is enabled, mixes and playbacks buffers of all AudioStreams. Finally, for
29  * each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all other
30  * buffers and sends back the encoded packets. An AudioGroup does nothing if
31  * there is no AudioStream in it.
32  *
33  * <p>Few things must be noticed before using these classes. The performance is
34  * highly related to the system load and the network bandwidth. Usually a
35  * simpler {@link AudioCodec} costs fewer CPU cycles but requires more network
36  * bandwidth, and vise versa. Using two AudioStreams at the same time not only
37  * doubles the load but also the bandwidth. The condition varies from one device
38  * to another, and developers must choose the right combination in order to get
39  * the best result.
40  *
41  * <p>It is sometimes useful to keep multiple AudioGroups at the same time. For
42  * example, a Voice over IP (VoIP) application might want to put a conference
43  * call on hold in order to make a new call but still allow people in the
44  * previous call to talk to each other. This can be done easily using two
45  * AudioGroups, but there are some limitations. Since the speaker and the
46  * microphone are shared globally, only one AudioGroup is allowed to run in
47  * modes other than {@link #MODE_ON_HOLD}. In addition, before adding an
48  * AudioStream into an AudioGroup, one should always put all other AudioGroups
49  * into {@link #MODE_ON_HOLD}. That will make sure the audio driver correctly
50  * initialized.
51  * @hide
52  */
53 public class AudioGroup {
54     /**
55      * This mode is similar to {@link #MODE_NORMAL} except the speaker and
56      * the microphone are disabled.
57      */
58     public static final int MODE_ON_HOLD = 0;
59 
60     /**
61      * This mode is similar to {@link #MODE_NORMAL} except the microphone is
62      * muted.
63      */
64     public static final int MODE_MUTED = 1;
65 
66     /**
67      * This mode indicates that the speaker, the microphone, and all
68      * {@link AudioStream}s in the group are enabled. First, the packets
69      * received from the streams are decoded and mixed with the audio recorded
70      * from the microphone. Then, the results are played back to the speaker,
71      * encoded and sent back to each stream.
72      */
73     public static final int MODE_NORMAL = 2;
74 
75     /**
76      * This mode is similar to {@link #MODE_NORMAL} except the echo suppression
77      * is enabled. It should be only used when the speaker phone is on.
78      */
79     public static final int MODE_ECHO_SUPPRESSION = 3;
80 
81     private final Map<AudioStream, Integer> mStreams;
82     private int mMode = MODE_ON_HOLD;
83 
84     private int mNative;
85     static {
86         System.loadLibrary("rtp_jni");
87     }
88 
89     /**
90      * Creates an empty AudioGroup.
91      */
AudioGroup()92     public AudioGroup() {
93         mStreams = new HashMap<AudioStream, Integer>();
94     }
95 
96     /**
97      * Returns the current mode.
98      */
getMode()99     public int getMode() {
100         return mMode;
101     }
102 
103     /**
104      * Changes the current mode. It must be one of {@link #MODE_ON_HOLD},
105      * {@link #MODE_MUTED}, {@link #MODE_NORMAL}, and
106      * {@link #MODE_ECHO_SUPPRESSION}.
107      *
108      * @param mode The mode to change to.
109      * @throws IllegalArgumentException if the mode is invalid.
110      */
setMode(int mode)111     public synchronized native void setMode(int mode);
112 
add(int mode, int socket, String remoteAddress, int remotePort, String codecSpec, int dtmfType)113     private native void add(int mode, int socket, String remoteAddress,
114             int remotePort, String codecSpec, int dtmfType);
115 
add(AudioStream stream, AudioCodec codec, int dtmfType)116     synchronized void add(AudioStream stream, AudioCodec codec, int dtmfType) {
117         if (!mStreams.containsKey(stream)) {
118             try {
119                 int socket = stream.dup();
120                 String codecSpec = String.format("%d %s %s", codec.type,
121                         codec.rtpmap, codec.fmtp);
122                 add(stream.getMode(), socket,
123                         stream.getRemoteAddress().getHostAddress(),
124                         stream.getRemotePort(), codecSpec, dtmfType);
125                 mStreams.put(stream, socket);
126             } catch (NullPointerException e) {
127                 throw new IllegalStateException(e);
128             }
129         }
130     }
131 
remove(int socket)132     private native void remove(int socket);
133 
remove(AudioStream stream)134     synchronized void remove(AudioStream stream) {
135         Integer socket = mStreams.remove(stream);
136         if (socket != null) {
137             remove(socket);
138         }
139     }
140 
141     /**
142      * Sends a DTMF digit to every {@link AudioStream} in this group. Currently
143      * only event {@code 0} to {@code 15} are supported.
144      *
145      * @throws IllegalArgumentException if the event is invalid.
146      */
sendDtmf(int event)147     public native synchronized void sendDtmf(int event);
148 
149     /**
150      * Removes every {@link AudioStream} in this group.
151      */
clear()152     public synchronized void clear() {
153         remove(-1);
154     }
155 
156     @Override
finalize()157     protected void finalize() throws Throwable {
158         clear();
159         super.finalize();
160     }
161 }
162