1 /* 2 * Copyright (C) 2008 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 com.android.mediaframeworktest.unit; 18 19 import android.util.Log; 20 import android.media.MediaRecorder; 21 import android.test.AndroidTestCase; 22 23 /** 24 * A template class for running a method under test in all possible 25 * states of a MediaRecorder object. 26 * 27 * @see com.android.mediaframeworktest.unit.MediaRecorderStopStateUnitTest 28 * for an example of using this class. 29 * 30 * A typical concrete unit test class would implement the 31 * MediaRecorderMethodUnderTest interface and have a reference to an object of 32 * this class. Then it calls runTestOnMethod() to actually perform the unit 33 * tests. It is recommended that the toString() method of the concrete unit test 34 * class be overridden to use the actual method name under test for logging 35 * purpose. 36 * 37 */ 38 class MediaRecorderStateUnitTestTemplate extends AndroidTestCase { 39 public static final String RECORD_OUTPUT_PATH = "/sdcard/recording.3gp"; 40 public static final int OUTPUT_FORMAT= MediaRecorder.OutputFormat.THREE_GPP; 41 public static final int AUDIO_ENCODER = MediaRecorder.AudioEncoder.AMR_NB; 42 public static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC; 43 private static final String TAG = "MediaRecorderStateUnitTest"; 44 private MediaRecorderStateErrors mStateErrors = new MediaRecorderStateErrors(); 45 private MediaRecorder mMediaRecorder = new MediaRecorder(); 46 private MediaRecorderStateErrors.MediaRecorderState mMediaRecorderState = null; 47 private MediaRecorderMethodUnderTest mMethodUnderTest = null; 48 49 /** 50 * Runs the given method under test in all possible states of a MediaRecorder 51 * object. 52 * 53 * @param testMethod the method under test. 54 */ 55 public void runTestOnMethod(MediaRecorderMethodUnderTest testMethod) { 56 mMethodUnderTest = testMethod; 57 if (mMethodUnderTest != null) { // Method under test has been set? 58 checkMethodUnderTestInAllPossibleStates(); 59 mMethodUnderTest.checkStateErrors(mStateErrors); 60 cleanUp(); 61 } 62 } 63 64 /* 65 * Calls method under test in the given state of the MediaRecorder object. 66 * 67 * @param state the MediaRecorder state in which the method under test is called. 68 */ 69 private void callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState state) { 70 Log.v(TAG, "call " + mMethodUnderTest + ": started in state " + state); 71 setMediaRecorderToState(state); 72 try { 73 mMethodUnderTest.invokeMethodUnderTest(mMediaRecorder); 74 } catch(Exception e) { 75 setStateError(mMediaRecorderState, true); 76 } 77 Log.v(TAG, "call " + mMethodUnderTest + ": ended in state " + state); 78 } 79 80 /* 81 * The following setMediaRecorderToXXXStateXXX methods sets the MediaRecorder 82 * object to the corresponding state, given the assumption that reset() 83 * always resets the MediaRecorder object to Initial (after reset) state. 84 */ 85 private void setMediaRecorderToInitialStateAfterReset() { 86 try { 87 mMediaRecorder.reset(); 88 } catch(Exception e) { 89 fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown."); 90 } 91 } 92 93 // FIXME: 94 // In the past, stop() == reset(). 95 // However, this is no longer true. The plan is to have a STOPPED state. 96 // and from STOPPED state, start can be called without the need to 97 // do the recording configuration again. 98 private void setMediaRecorderToInitialStateAfterStop() { 99 try { 100 mMediaRecorder.reset(); 101 /* 102 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 103 mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); 104 mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); 105 mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); 106 mMediaRecorder.prepare(); 107 mMediaRecorder.start(); 108 mMediaRecorder.stop(); 109 */ 110 } catch(Exception e) { 111 fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown."); 112 } 113 } 114 115 private void setMediaRecorderToInitializedState() { 116 try { 117 mMediaRecorder.reset(); 118 if (mMethodUnderTest.toString() != "setAudioSource()") { 119 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 120 } 121 } catch(Exception e) { 122 fail("setMediaRecorderToInitializedState: Exception " + e.getClass().getName() + " was thrown."); 123 } 124 } 125 126 private void setMediaRecorderToPreparedState() { 127 try { 128 mMediaRecorder.reset(); 129 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 130 mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); 131 mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); 132 mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); 133 mMediaRecorder.prepare(); 134 } catch(Exception e) { 135 fail("setMediaRecorderToPreparedState: Exception " + e.getClass().getName() + " was thrown."); 136 } 137 } 138 139 private void setMediaRecorderToRecordingState() { 140 try { 141 mMediaRecorder.reset(); 142 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 143 mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); 144 mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); 145 mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); 146 mMediaRecorder.prepare(); 147 mMediaRecorder.start(); 148 } catch(Exception e) { 149 fail("setMediaRecorderToRecordingState: Exception " + e.getClass().getName() + " was thrown."); 150 } 151 } 152 153 private void setMediaRecorderToDataSourceConfiguredState() { 154 try { 155 mMediaRecorder.reset(); 156 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 157 mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); 158 159 /* Skip setAudioEncoder() and setOutputFile() calls if 160 * the method under test is setAudioEncoder() since this 161 * method can only be called once even in the DATASOURCECONFIGURED state 162 */ 163 if (mMethodUnderTest.toString() != "setAudioEncoder()") { 164 mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); 165 } 166 167 if (mMethodUnderTest.toString() != "setOutputFile()") { 168 mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); 169 } 170 } catch(Exception e) { 171 fail("setMediaRecorderToDataSourceConfiguredState: Exception " + e.getClass().getName() + " was thrown."); 172 } 173 } 174 175 /* 176 * There are a lot of ways to force the MediaRecorder object to enter 177 * the Error state. We arbitrary choose one here. 178 */ 179 private void setMediaRecorderToErrorState() { 180 try { 181 mMediaRecorder.reset(); 182 183 /* Skip setAudioSource() if the method under test is setAudioEncoder() 184 * Because, otherwise, it is valid to call setAudioEncoder() after 185 * start() since start() will fail, and then the mMediaRecorder 186 * won't be set to the Error state 187 */ 188 if (mMethodUnderTest.toString() != "setAudioEncoder()") { 189 mMediaRecorder.setAudioSource(AUDIO_SOURCE); 190 } 191 192 /* Skip setOutputFormat if the method under test is setOutputFile() 193 * Because, otherwise, it is valid to call setOutputFile() after 194 * start() since start() will fail, and then the mMediaRecorder 195 * won't be set to the Error state 196 */ 197 if (mMethodUnderTest.toString() != "setOutputFile()") { 198 mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); 199 } 200 201 mMediaRecorder.start(); 202 } catch(Exception e) { 203 if (!(e instanceof IllegalStateException)) { 204 fail("setMediaRecorderToErrorState: Exception " + e.getClass().getName() + " was thrown."); 205 } 206 } 207 Log.v(TAG, "setMediaRecorderToErrorState: done."); 208 } 209 210 /* 211 * Sets the state of the MediaRecorder object to the specified one. 212 * 213 * @param state the state of the MediaRecorder object. 214 */ 215 private void setMediaRecorderToState(MediaRecorderStateErrors.MediaRecorderState state) { 216 mMediaRecorderState = state; 217 switch(state) { 218 case INITIAL: 219 // Does nothing. 220 break; 221 case INITIAL_AFTER_RESET: 222 setMediaRecorderToInitialStateAfterReset(); 223 break; 224 case INITIAL_AFTER_STOP: 225 setMediaRecorderToInitialStateAfterStop(); 226 break; 227 case INITIALIZED: 228 setMediaRecorderToInitializedState(); 229 break; 230 case DATASOURCECONFIGURED: 231 setMediaRecorderToDataSourceConfiguredState(); 232 break; 233 case PREPARED: 234 setMediaRecorderToPreparedState(); 235 break; 236 case RECORDING: 237 setMediaRecorderToRecordingState(); 238 break; 239 case ERROR: 240 setMediaRecorderToErrorState(); 241 break; 242 } 243 } 244 245 /* 246 * Sets the error value of the corresponding state to the given error. 247 * 248 * @param state the state of the MediaRecorder object. 249 * @param error the value of the state error to be set. 250 */ 251 private void setStateError(MediaRecorderStateErrors.MediaRecorderState state, boolean error) { 252 switch(state) { 253 case INITIAL: 254 mStateErrors.errorInInitialState = error; 255 break; 256 case INITIAL_AFTER_RESET: 257 mStateErrors.errorInInitialStateAfterReset = error; 258 break; 259 case INITIAL_AFTER_STOP: 260 mStateErrors.errorInInitialStateAfterStop = error; 261 break; 262 case INITIALIZED: 263 mStateErrors.errorInInitializedState = error; 264 break; 265 case DATASOURCECONFIGURED: 266 mStateErrors.errorInDataSourceConfiguredState = error; 267 break; 268 case PREPARED: 269 mStateErrors.errorInPreparedState = error; 270 break; 271 case RECORDING: 272 mStateErrors.errorInRecordingState = error; 273 break; 274 case ERROR: 275 mStateErrors.errorInErrorState = error; 276 break; 277 } 278 } 279 280 private void checkInitialState() { 281 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL); 282 } 283 284 private void checkInitialStateAfterReset() { 285 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_RESET); 286 } 287 288 private void checkInitialStateAfterStop() { 289 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_STOP); 290 } 291 292 private void checkInitializedState() { 293 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIALIZED); 294 } 295 296 private void checkPreparedState() { 297 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.PREPARED); 298 } 299 300 private void checkRecordingState() { 301 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.RECORDING); 302 } 303 304 private void checkDataSourceConfiguredState() { 305 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.DATASOURCECONFIGURED); 306 } 307 308 private void checkErrorState() { 309 callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.ERROR); 310 } 311 312 /* 313 * Checks the given method under test in all possible states of the MediaRecorder object. 314 */ 315 private void checkMethodUnderTestInAllPossibleStates() { 316 // Must be called first. 317 checkInitialState(); 318 319 // The sequence of the following method calls should not 320 // affect the test results. 321 checkErrorState(); 322 checkInitialStateAfterReset(); 323 checkInitialStateAfterStop(); 324 checkInitializedState(); 325 checkRecordingState(); 326 checkDataSourceConfiguredState(); 327 checkPreparedState(); 328 } 329 330 /* 331 * Cleans up all the internal object references. 332 */ 333 private void cleanUp() { 334 mMediaRecorder.release(); 335 mMediaRecorder = null; 336 mMediaRecorderState = null; 337 mStateErrors = null; 338 mMethodUnderTest = null; 339 } 340 } 341