1363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang/*
2363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Copyright (C) 2010 The Android Open Source Project
3363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
4363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License");
5363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * you may not use this file except in compliance with the License.
6363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * You may obtain a copy of the License at
7363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
8363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *      http://www.apache.org/licenses/LICENSE-2.0
9363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang *
10363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * Unless required by applicable law or agreed to in writing, software
11363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS,
12363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * See the License for the specific language governing permissions and
14363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang * limitations under the License.
15363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang */
16363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
17363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangpackage android.net.rtp;
18363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
19363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport java.net.InetAddress;
20363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangimport java.net.SocketException;
21363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
22363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang/**
2332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * An AudioStream is a {@link RtpStream} which carrys audio payloads over
2432e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * Real-time Transport Protocol (RTP). Two different classes are developed in
2532e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * order to support various usages such as audio conferencing. An AudioStream
2632e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * represents a remote endpoint which consists of a network mapping and a
2732e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * configured {@link AudioCodec}. On the other side, An {@link AudioGroup}
2832e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * represents a local endpoint which mixes all the AudioStreams and optionally
2932e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * interacts with the speaker and the microphone at the same time. The simplest
30c52f5b2ec5e13ab3d9ab016e6cab757d4ecb45c7Chia-chi Yeh * usage includes one for each endpoints. For other combinations, developers
31c52f5b2ec5e13ab3d9ab016e6cab757d4ecb45c7Chia-chi Yeh * should be aware of the limitations described in {@link AudioGroup}.
3232e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh *
3332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * <p>An AudioStream becomes busy when it joins an AudioGroup. In this case most
3432e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * of the setter methods are disabled. This is designed to ease the task of
3532e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * managing native resources. One can always make an AudioStream leave its
3632e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * AudioGroup by calling {@link #join(AudioGroup)} with {@code null} and put it
3753aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh * back after the modification is done.</p>
3832e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh *
3953aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh * <p class="note">Using this class requires
4053aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh * {@link android.Manifest.permission#INTERNET} permission.</p>
4153aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh *
4253aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh * @see RtpStream
4332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh * @see AudioGroup
44363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang */
45363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wangpublic class AudioStream extends RtpStream {
46363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private AudioCodec mCodec;
47363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private int mDtmfType = -1;
48363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    private AudioGroup mGroup;
49363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
50363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
51363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Creates an AudioStream on the given local address. Note that the local
52363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * port is assigned automatically to conform with RFC 3550.
53363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
54363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param address The network address of the local host to bind to.
55363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws SocketException if the address cannot be bound or a problem
56363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *     occurs during binding.
57363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
58363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public AudioStream(InetAddress address) throws SocketException {
59363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        super(address);
60363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
61363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
62363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
6332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh     * Returns {@code true} if the stream has already joined an
6432e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh     * {@link AudioGroup}.
65363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
66363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    @Override
67363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public final boolean isBusy() {
68363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        return mGroup != null;
69363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
70363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
71363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
72363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Returns the joined {@link AudioGroup}.
73363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
7432e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh    public AudioGroup getGroup() {
75363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        return mGroup;
76363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
77363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
78363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
79363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Joins an {@link AudioGroup}. Each stream can join only one group at a
80363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * time. The group can be changed by passing a different one or removed
81363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * by calling this method with {@code null}.
82363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
83363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param group The AudioGroup to join or {@code null} to leave.
84363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws IllegalStateException if the stream is not properly configured.
85363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @see AudioGroup
86363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
87363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void join(AudioGroup group) {
8853aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh        synchronized (this) {
8953aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            if (mGroup == group) {
9053aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh                return;
9153aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            }
9253aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            if (mGroup != null) {
9353aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh                mGroup.remove(this);
9453aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh                mGroup = null;
9553aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            }
9653aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            if (group != null) {
97e66950506c473e660f2e5762d7a71e13808be387Chia-chi Yeh                group.add(this);
9853aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh                mGroup = group;
9953aa6ef70d8692277f9403f94d43918ad9712dd0Chia-chi Yeh            }
100363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
101363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
102363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
103363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
10437adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * Returns the {@link AudioCodec}, or {@code null} if it is not set.
10537adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     *
10637adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * @see #setCodec(AudioCodec)
10737adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     */
10837adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    public AudioCodec getCodec() {
10937adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh        return mCodec;
11037adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    }
11137adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh
11237adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    /**
11332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh     * Sets the {@link AudioCodec}.
114363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
115363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param codec The AudioCodec to be used.
11632e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh     * @throws IllegalArgumentException if its type is used by DTMF.
117363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws IllegalStateException if the stream is busy.
118363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
11932e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh    public void setCodec(AudioCodec codec) {
120363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (isBusy()) {
121363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new IllegalStateException("Busy");
122363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
12332e106b7bdd57c82ee67705871f6116d92bce79bChia-chi Yeh        if (codec.type == mDtmfType) {
124363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new IllegalArgumentException("The type is used by DTMF");
125363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
126363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        mCodec = codec;
127363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
128363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang
129363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    /**
13037adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * Returns the RTP payload type for dual-tone multi-frequency (DTMF) digits,
13137adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * or {@code -1} if it is not enabled.
13237adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     *
13337adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * @see #setDtmfType(int)
13437adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     */
13537adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    public int getDtmfType() {
13637adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh        return mDtmfType;
13737adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    }
13837adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh
13937adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh    /**
140363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * Sets the RTP payload type for dual-tone multi-frequency (DTMF) digits.
141363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * The primary usage is to send digits to the remote gateway to perform
142363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * certain tasks, such as second-stage dialing. According to RFC 2833, the
143363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * RTP payload type for DTMF is assigned dynamically, so it must be in the
144363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * range of 96 and 127. One can use {@code -1} to disable DTMF and free up
14537adc522f6bc074a688ffbef420a8627ef9a4b5bChia-chi Yeh     * the previous assigned type. This method cannot be called when the stream
146363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * already joined an {@link AudioGroup}.
147363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     *
148363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @param type The RTP payload type to be used or {@code -1} to disable it.
149363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws IllegalArgumentException if the type is invalid or used by codec.
150363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @throws IllegalStateException if the stream is busy.
151363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     * @see AudioGroup#sendDtmf(int)
152363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang     */
153363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    public void setDtmfType(int type) {
154363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (isBusy()) {
155363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            throw new IllegalStateException("Busy");
156363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
157363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        if (type != -1) {
158363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            if (type < 96 || type > 127) {
159363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang                throw new IllegalArgumentException("Invalid type");
160363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            }
161fb982db41060a2914cddb43200f3ee53627f8762Chia-chi Yeh            if (mCodec != null && type == mCodec.type) {
162363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang                throw new IllegalArgumentException("The type is used by codec");
163363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang            }
164363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        }
165363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang        mDtmfType = type;
166363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang    }
167363c2ab82cca4f095e9e0c8465e28f6d27a24bf8Chung-yih Wang}
168