198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/*
298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Copyright (C) 2010 The Android Open Source Project
398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License");
598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * you may not use this file except in compliance with the License.
698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * You may obtain a copy of the License at
798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *      http://www.apache.org/licenses/LICENSE-2.0
998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang *
1098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Unless required by applicable law or agreed to in writing, software
1198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS,
1298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * See the License for the specific language governing permissions and
1498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * limitations under the License.
1598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
1698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
1798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpackage android.net.rtp;
1898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
1998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport java.net.InetAddress;
2098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport java.net.SocketException;
2198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
2298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/**
237f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * An AudioStream is a {@link RtpStream} which carrys audio payloads over
247f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * Real-time Transport Protocol (RTP). Two different classes are developed in
257f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * order to support various usages such as audio conferencing. An AudioStream
267f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * represents a remote endpoint which consists of a network mapping and a
277f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * configured {@link AudioCodec}. On the other side, An {@link AudioGroup}
287f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * represents a local endpoint which mixes all the AudioStreams and optionally
297f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * interacts with the speaker and the microphone at the same time. The simplest
300a3e1f1851b26657b865ae3c91200c59dfc411feChia-chi Yeh * usage includes one for each endpoints. For other combinations, developers
310a3e1f1851b26657b865ae3c91200c59dfc411feChia-chi Yeh * should be aware of the limitations described in {@link AudioGroup}.
327f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh *
337f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * <p>An AudioStream becomes busy when it joins an AudioGroup. In this case most
347f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * of the setter methods are disabled. This is designed to ease the task of
357f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * managing native resources. One can always make an AudioStream leave its
367f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * AudioGroup by calling {@link #join(AudioGroup)} with {@code null} and put it
37a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh * back after the modification is done.</p>
387f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh *
39a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh * <p class="note">Using this class requires
40a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh * {@link android.Manifest.permission#INTERNET} permission.</p>
41a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh *
42a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh * @see RtpStream
437f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh * @see AudioGroup
4498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */
4598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpublic class AudioStream extends RtpStream {
4698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private AudioCodec mCodec;
4798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private int mDtmfType = -1;
4898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    private AudioGroup mGroup;
4998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
5098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
5198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Creates an AudioStream on the given local address. Note that the local
5298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * port is assigned automatically to conform with RFC 3550.
5398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
5498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param address The network address of the local host to bind to.
5598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws SocketException if the address cannot be bound or a problem
5698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *     occurs during binding.
5798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
5898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public AudioStream(InetAddress address) throws SocketException {
5998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        super(address);
6098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
6198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
6298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
637f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh     * Returns {@code true} if the stream has already joined an
647f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh     * {@link AudioGroup}.
6598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
6698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    @Override
6798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public final boolean isBusy() {
6898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return mGroup != null;
6998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
7098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
7198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
7298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Returns the joined {@link AudioGroup}.
7398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
747f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh    public AudioGroup getGroup() {
7598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        return mGroup;
7698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
7798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
7898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
7998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Joins an {@link AudioGroup}. Each stream can join only one group at a
8098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * time. The group can be changed by passing a different one or removed
8198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * by calling this method with {@code null}.
8298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
8398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param group The AudioGroup to join or {@code null} to leave.
8498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws IllegalStateException if the stream is not properly configured.
8598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @see AudioGroup
8698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
8798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void join(AudioGroup group) {
88a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh        synchronized (this) {
89a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            if (mGroup == group) {
90a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh                return;
91a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            }
92a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            if (mGroup != null) {
93a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh                mGroup.remove(this);
94a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh                mGroup = null;
95a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            }
96a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            if (group != null) {
972bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh                group.add(this);
98a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh                mGroup = group;
99a54e36694b3909ef367867eb7516b2d6f6031261Chia-chi Yeh            }
10098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
10198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
10298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
10398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
10407c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * Returns the {@link AudioCodec}, or {@code null} if it is not set.
10507c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     *
10607c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * @see #setCodec(AudioCodec)
10707c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     */
10807c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    public AudioCodec getCodec() {
10907c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh        return mCodec;
11007c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    }
11107c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh
11207c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    /**
1137f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh     * Sets the {@link AudioCodec}.
11498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
11598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param codec The AudioCodec to be used.
1167f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh     * @throws IllegalArgumentException if its type is used by DTMF.
11798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws IllegalStateException if the stream is busy.
11898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
1197f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh    public void setCodec(AudioCodec codec) {
12098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (isBusy()) {
12198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new IllegalStateException("Busy");
12298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
1237f383063fafc54a41f91540a41bf987003fd2502Chia-chi Yeh        if (codec.type == mDtmfType) {
12498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new IllegalArgumentException("The type is used by DTMF");
12598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
12698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        mCodec = codec;
12798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
12898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang
12998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    /**
13007c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * Returns the RTP payload type for dual-tone multi-frequency (DTMF) digits,
13107c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * or {@code -1} if it is not enabled.
13207c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     *
13307c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * @see #setDtmfType(int)
13407c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     */
13507c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    public int getDtmfType() {
13607c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh        return mDtmfType;
13707c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    }
13807c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh
13907c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh    /**
14098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * Sets the RTP payload type for dual-tone multi-frequency (DTMF) digits.
14198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * The primary usage is to send digits to the remote gateway to perform
14298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * certain tasks, such as second-stage dialing. According to RFC 2833, the
14398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * RTP payload type for DTMF is assigned dynamically, so it must be in the
14498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * range of 96 and 127. One can use {@code -1} to disable DTMF and free up
14507c7dc5e0b1465a83fbe33d3b94f7ebceccbdee0Chia-chi Yeh     * the previous assigned type. This method cannot be called when the stream
14698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * already joined an {@link AudioGroup}.
14798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     *
14898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @param type The RTP payload type to be used or {@code -1} to disable it.
14998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws IllegalArgumentException if the type is invalid or used by codec.
15098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @throws IllegalStateException if the stream is busy.
15198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     * @see AudioGroup#sendDtmf(int)
15298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang     */
15398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    public void setDtmfType(int type) {
15498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (isBusy()) {
15598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            throw new IllegalStateException("Busy");
15698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
15798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        if (type != -1) {
15898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            if (type < 96 || type > 127) {
15998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                throw new IllegalArgumentException("Invalid type");
16098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            }
161a7857fbfdfccacb95306e32511f57f1a017b0e31Chia-chi Yeh            if (mCodec != null && type == mCodec.type) {
16298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang                throw new IllegalArgumentException("The type is used by codec");
16398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang            }
16498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        }
16598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang        mDtmfType = type;
16698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang    }
16798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang}
168