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
17package android.net.rtp;
18
19import java.util.Arrays;
20
21/**
22 * This class defines a collection of audio codecs to be used with
23 * {@link AudioStream}s. Their parameters are designed to be exchanged using
24 * Session Description Protocol (SDP). Most of the values listed here can be
25 * found in RFC 3551, while others are described in separated standards.
26 *
27 * <p>Few simple configurations are defined as public static instances for the
28 * convenience of direct uses. More complicated ones could be obtained using
29 * {@link #getCodec(int, String, String)}. For example, one can use the
30 * following snippet to create a mode-1-only AMR codec.</p>
31 * <pre>
32 * AudioCodec codec = AudioCodec.getCodec(100, "AMR/8000", "mode-set=1");
33 * </pre>
34 *
35 * @see AudioStream
36 */
37public class AudioCodec {
38    /**
39     * The RTP payload type of the encoding.
40     */
41    public final int type;
42
43    /**
44     * The encoding parameters to be used in the corresponding SDP attribute.
45     */
46    public final String rtpmap;
47
48    /**
49     * The format parameters to be used in the corresponding SDP attribute.
50     */
51    public final String fmtp;
52
53    /**
54     * G.711 u-law audio codec.
55     */
56    public static final AudioCodec PCMU = new AudioCodec(0, "PCMU/8000", null);
57
58    /**
59     * G.711 a-law audio codec.
60     */
61    public static final AudioCodec PCMA = new AudioCodec(8, "PCMA/8000", null);
62
63    /**
64     * GSM Full-Rate audio codec, also known as GSM-FR, GSM 06.10, GSM, or
65     * simply FR.
66     */
67    public static final AudioCodec GSM = new AudioCodec(3, "GSM/8000", null);
68
69    /**
70     * GSM Enhanced Full-Rate audio codec, also known as GSM-EFR, GSM 06.60, or
71     * simply EFR.
72     */
73    public static final AudioCodec GSM_EFR = new AudioCodec(96, "GSM-EFR/8000", null);
74
75    /**
76     * Adaptive Multi-Rate narrowband audio codec, also known as AMR or AMR-NB.
77     * Currently CRC, robust sorting, and interleaving are not supported. See
78     * more details about these features in RFC 4867.
79     */
80    public static final AudioCodec AMR = new AudioCodec(97, "AMR/8000", null);
81
82    private static final AudioCodec[] sCodecs = {GSM_EFR, AMR, GSM, PCMU, PCMA};
83
84    private AudioCodec(int type, String rtpmap, String fmtp) {
85        this.type = type;
86        this.rtpmap = rtpmap;
87        this.fmtp = fmtp;
88    }
89
90    /**
91     * Returns system supported audio codecs.
92     */
93    public static AudioCodec[] getCodecs() {
94        return Arrays.copyOf(sCodecs, sCodecs.length);
95    }
96
97    /**
98     * Creates an AudioCodec according to the given configuration.
99     *
100     * @param type The payload type of the encoding defined in RTP/AVP.
101     * @param rtpmap The encoding parameters specified in the corresponding SDP
102     *     attribute, or null if it is not available.
103     * @param fmtp The format parameters specified in the corresponding SDP
104     *     attribute, or null if it is not available.
105     * @return The configured AudioCodec or {@code null} if it is not supported.
106     */
107    public static AudioCodec getCodec(int type, String rtpmap, String fmtp) {
108        if (type < 0 || type > 127) {
109            return null;
110        }
111
112        AudioCodec hint = null;
113        if (rtpmap != null) {
114            String clue = rtpmap.trim().toUpperCase();
115            for (AudioCodec codec : sCodecs) {
116                if (clue.startsWith(codec.rtpmap)) {
117                    String channels = clue.substring(codec.rtpmap.length());
118                    if (channels.length() == 0 || channels.equals("/1")) {
119                        hint = codec;
120                    }
121                    break;
122                }
123            }
124        } else if (type < 96) {
125            for (AudioCodec codec : sCodecs) {
126                if (type == codec.type) {
127                    hint = codec;
128                    rtpmap = codec.rtpmap;
129                    break;
130                }
131            }
132        }
133
134        if (hint == null) {
135            return null;
136        }
137        if (hint == AMR && fmtp != null) {
138            String clue = fmtp.toLowerCase();
139            if (clue.contains("crc=1") || clue.contains("robust-sorting=1") ||
140                    clue.contains("interleaving=")) {
141                return null;
142            }
143        }
144        return new AudioCodec(type, rtpmap, fmtp);
145    }
146}
147