1 /* 2 * Copyright (C) 2012 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 package android.net.rtp.cts; 17 18 import android.content.Context; 19 import android.media.AudioManager; 20 import android.net.rtp.AudioCodec; 21 import android.net.rtp.AudioGroup; 22 import android.net.rtp.AudioStream; 23 import android.net.rtp.RtpStream; 24 import android.os.Build; 25 import android.platform.test.annotations.AppModeFull; 26 import android.test.AndroidTestCase; 27 28 import androidx.core.os.BuildCompat; 29 30 import java.net.DatagramPacket; 31 import java.net.DatagramSocket; 32 import java.net.InetAddress; 33 34 @AppModeFull(reason = "RtpStream cannot create in instant app mode") 35 public class AudioGroupTest extends AndroidTestCase { 36 37 private static final String TAG = AudioGroupTest.class.getSimpleName(); 38 39 private AudioManager mAudioManager; 40 41 private AudioStream mStreamA; 42 private DatagramSocket mSocketA; 43 private AudioStream mStreamB; 44 private DatagramSocket mSocketB; 45 private AudioGroup mGroup; 46 47 @Override setUp()48 public void setUp() throws Exception { 49 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 50 mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); 51 52 InetAddress local = InetAddress.getByName("::1"); 53 54 mStreamA = new AudioStream(local); 55 mStreamA.setMode(RtpStream.MODE_NORMAL); 56 mStreamA.setCodec(AudioCodec.PCMU); 57 mSocketA = new DatagramSocket(); 58 mSocketA.connect(mStreamA.getLocalAddress(), mStreamA.getLocalPort()); 59 mStreamA.associate(mSocketA.getLocalAddress(), mSocketA.getLocalPort()); 60 61 mStreamB = new AudioStream(local); 62 mStreamB.setMode(RtpStream.MODE_NORMAL); 63 mStreamB.setCodec(AudioCodec.PCMU); 64 mSocketB = new DatagramSocket(); 65 mSocketB.connect(mStreamB.getLocalAddress(), mStreamB.getLocalPort()); 66 mStreamB.associate(mSocketB.getLocalAddress(), mSocketB.getLocalPort()); 67 68 // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R) 69 mGroup = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR() 70 ? new AudioGroup(mContext) 71 : new AudioGroup(); // Constructor with context argument was introduced in R 72 } 73 74 @Override tearDown()75 public void tearDown() throws Exception { 76 mGroup.clear(); 77 mStreamA.release(); 78 mSocketA.close(); 79 mStreamB.release(); 80 mSocketB.close(); 81 mAudioManager.setMode(AudioManager.MODE_NORMAL); 82 } 83 assertPacket(DatagramSocket socket, int length)84 private void assertPacket(DatagramSocket socket, int length) throws Exception { 85 DatagramPacket packet = new DatagramPacket(new byte[length + 1], length + 1); 86 socket.setSoTimeout(3000); 87 socket.receive(packet); 88 assertEquals(packet.getLength(), length); 89 } 90 drain(DatagramSocket socket)91 private void drain(DatagramSocket socket) throws Exception { 92 DatagramPacket packet = new DatagramPacket(new byte[1], 1); 93 socket.setSoTimeout(1); 94 try { 95 // Drain the socket by retrieving all the packets queued on it. 96 // A SocketTimeoutException will be thrown when it becomes empty. 97 while (true) { 98 socket.receive(packet); 99 } 100 } catch (Exception e) { 101 // ignore. 102 } 103 } 104 testTraffic()105 public void testTraffic() throws Exception { 106 mStreamA.join(mGroup); 107 assertPacket(mSocketA, 12 + 160); 108 109 mStreamB.join(mGroup); 110 assertPacket(mSocketB, 12 + 160); 111 112 mStreamA.join(null); 113 drain(mSocketA); 114 115 drain(mSocketB); 116 assertPacket(mSocketB, 12 + 160); 117 118 mStreamA.join(mGroup); 119 assertPacket(mSocketA, 12 + 160); 120 } 121 testSetMode()122 public void testSetMode() throws Exception { 123 mGroup.setMode(AudioGroup.MODE_NORMAL); 124 assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); 125 126 mGroup.setMode(AudioGroup.MODE_MUTED); 127 assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); 128 129 mStreamA.join(mGroup); 130 mStreamB.join(mGroup); 131 132 mGroup.setMode(AudioGroup.MODE_NORMAL); 133 assertEquals(mGroup.getMode(), AudioGroup.MODE_NORMAL); 134 135 mGroup.setMode(AudioGroup.MODE_MUTED); 136 assertEquals(mGroup.getMode(), AudioGroup.MODE_MUTED); 137 } 138 testAdd()139 public void testAdd() throws Exception { 140 mStreamA.join(mGroup); 141 assertEquals(mGroup.getStreams().length, 1); 142 143 mStreamB.join(mGroup); 144 assertEquals(mGroup.getStreams().length, 2); 145 146 mStreamA.join(mGroup); 147 assertEquals(mGroup.getStreams().length, 2); 148 } 149 testRemove()150 public void testRemove() throws Exception { 151 mStreamA.join(mGroup); 152 assertEquals(mGroup.getStreams().length, 1); 153 154 mStreamA.join(null); 155 assertEquals(mGroup.getStreams().length, 0); 156 157 mStreamA.join(mGroup); 158 assertEquals(mGroup.getStreams().length, 1); 159 } 160 testClear()161 public void testClear() throws Exception { 162 mStreamA.join(mGroup); 163 mStreamB.join(mGroup); 164 mGroup.clear(); 165 166 assertEquals(mGroup.getStreams().length, 0); 167 assertFalse(mStreamA.isBusy()); 168 assertFalse(mStreamB.isBusy()); 169 } 170 testDoubleClear()171 public void testDoubleClear() throws Exception { 172 mStreamA.join(mGroup); 173 mStreamB.join(mGroup); 174 mGroup.clear(); 175 mGroup.clear(); 176 } 177 } 178