AudioTrack.java revision 0f76d9b1c2d93a19b436dcbfef9fc46a2712d195
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.media.videoeditor; 18 19import java.io.IOException; 20import java.lang.ref.SoftReference; 21 22/** 23 * This class allows to handle an audio track. This audio file is mixed with the 24 * audio samples of the media items. 25 * {@hide} 26 */ 27public class AudioTrack { 28 // Instance variables 29 private final String mUniqueId; 30 private final String mFilename; 31 private long mStartTimeMs; 32 private long mTimelineDurationMs; 33 private int mVolumePercent; 34 private long mBeginBoundaryTimeMs; 35 private long mEndBoundaryTimeMs; 36 private boolean mLoop; 37 private boolean mMuted; 38 39 private final long mDurationMs; 40 private final int mAudioChannels; 41 private final int mAudioType; 42 private final int mAudioBitrate; 43 private final int mAudioSamplingFrequency; 44 45 // Ducking variables 46 private int mDuckingThreshold; 47 private int mDuckedTrackVolume; 48 private boolean mIsDuckingEnabled; 49 50 // The audio waveform filename 51 private String mAudioWaveformFilename; 52 // The audio waveform data 53 private SoftReference<WaveformData> mWaveformData; 54 55 /** 56 * An object of this type cannot be instantiated by using the default 57 * constructor 58 */ 59 @SuppressWarnings("unused") 60 private AudioTrack() throws IOException { 61 this(null, null, null); 62 } 63 64 /** 65 * Constructor 66 * 67 * @param editor The video editor reference 68 * @param audioTrackId The audio track id 69 * @param filename The absolute file name 70 * 71 * @throws IOException if file is not found 72 * @throws IllegalArgumentException if file format is not supported or if 73 * the codec is not supported 74 */ 75 public AudioTrack(VideoEditor editor, String audioTrackId, String filename) 76 throws IOException { 77 mUniqueId = audioTrackId; 78 mFilename = filename; 79 mStartTimeMs = 0; 80 // TODO: This value represents to the duration of the audio file 81 mDurationMs = 300000; 82 // TODO: This value needs to be read from the audio track of the source 83 // file 84 mAudioChannels = 2; 85 mAudioType = MediaProperties.ACODEC_AAC_LC; 86 mAudioBitrate = 128000; 87 mAudioSamplingFrequency = 44100; 88 89 mTimelineDurationMs = mDurationMs; 90 mVolumePercent = 100; 91 92 // Play the entire audio track 93 mBeginBoundaryTimeMs = 0; 94 mEndBoundaryTimeMs = mDurationMs; 95 96 // By default loop is disabled 97 mLoop = false; 98 99 // By default the audio track is not muted 100 mMuted = false; 101 102 // Ducking is enabled by default 103 mDuckingThreshold = 0; 104 mDuckedTrackVolume = 0; 105 mIsDuckingEnabled = false; 106 107 // The audio waveform file is generated later 108 mAudioWaveformFilename = null; 109 mWaveformData = null; 110 } 111 112 /** 113 * Constructor 114 * 115 * @param editor The video editor reference 116 * @param audioTrackId The audio track id 117 * @param filename The audio filename 118 * @param startTimeMs the start time in milliseconds (relative to the 119 * timeline) 120 * @param beginMs start time in the audio track in milliseconds (relative to 121 * the beginning of the audio track) 122 * @param endMs end time in the audio track in milliseconds (relative to the 123 * beginning of the audio track) 124 * @param loop true to loop the audio track 125 * @param volume The volume in percentage 126 * @param muted true if the audio track is muted 127 * @param threshold Ducking will be activated when the relative energy in 128 * the media items audio signal goes above this value. The valid 129 * range of values is 0 to 100. 130 * @param duckedTrackVolume The relative volume of the audio track when ducking 131 * is active. The valid range of values is 0 to 100. 132 * @param audioWaveformFilename The name of the waveform file 133 * 134 * @throws IOException if file is not found 135 */ 136 AudioTrack(VideoEditor editor, String audioTrackId, String filename, long startTimeMs, 137 long beginMs, long endMs, boolean loop, int volume, boolean muted, 138 boolean duckingEnabled, int duckThreshold, int duckedTrackVolume, 139 String audioWaveformFilename) throws IOException { 140 mUniqueId = audioTrackId; 141 mFilename = filename; 142 mStartTimeMs = startTimeMs; 143 144 // TODO: This value represents to the duration of the audio file 145 mDurationMs = 300000; 146 147 // TODO: This value needs to be read from the audio track of the source 148 // file 149 mAudioChannels = 2; 150 mAudioType = MediaProperties.ACODEC_AAC_LC; 151 mAudioBitrate = 128000; 152 mAudioSamplingFrequency = 44100; 153 154 mTimelineDurationMs = endMs - beginMs; 155 mVolumePercent = volume; 156 157 mBeginBoundaryTimeMs = beginMs; 158 mEndBoundaryTimeMs = endMs; 159 160 mLoop = loop; 161 mMuted = muted; 162 163 mIsDuckingEnabled = duckingEnabled; 164 mDuckingThreshold = duckThreshold; 165 mDuckedTrackVolume = duckedTrackVolume; 166 167 mAudioWaveformFilename = audioWaveformFilename; 168 if (audioWaveformFilename != null) { 169 mWaveformData = 170 new SoftReference<WaveformData>(new WaveformData(audioWaveformFilename)); 171 } else { 172 mWaveformData = null; 173 } 174 } 175 176 /** 177 * @return The id of the audio track 178 */ 179 public String getId() { 180 return mUniqueId; 181 } 182 183 /** 184 * Get the filename source for this audio track. 185 * 186 * @return The filename as an absolute file name 187 */ 188 public String getFilename() { 189 return mFilename; 190 } 191 192 /** 193 * @return The number of audio channels in the source of this audio track 194 */ 195 public int getAudioChannels() { 196 return mAudioChannels; 197 } 198 199 /** 200 * @return The audio codec of the source of this audio track 201 */ 202 public int getAudioType() { 203 return mAudioType; 204 } 205 206 /** 207 * @return The audio sample frequency of the audio track 208 */ 209 public int getAudioSamplingFrequency() { 210 return mAudioSamplingFrequency; 211 } 212 213 /** 214 * @return The audio bitrate of the audio track 215 */ 216 public int getAudioBitrate() { 217 return mAudioBitrate; 218 } 219 220 /** 221 * Set the volume of this audio track as percentage of the volume in the 222 * original audio source file. 223 * 224 * @param volumePercent Percentage of the volume to apply. If it is set to 225 * 0, then volume becomes mute. It it is set to 100, then volume 226 * is same as original volume. It it is set to 200, then volume 227 * is doubled (provided that volume amplification is supported) 228 * 229 * @throws UnsupportedOperationException if volume amplification is 230 * requested and is not supported. 231 */ 232 public void setVolume(int volumePercent) { 233 mVolumePercent = volumePercent; 234 } 235 236 /** 237 * Get the volume of the audio track as percentage of the volume in the 238 * original audio source file. 239 * 240 * @return The volume in percentage 241 */ 242 public int getVolume() { 243 return mVolumePercent; 244 } 245 246 /** 247 * @param muted true to mute the audio track 248 */ 249 public void setMute(boolean muted) { 250 mMuted = muted; 251 } 252 253 /** 254 * @return true if the audio track is muted 255 */ 256 public boolean isMuted() { 257 return mMuted; 258 } 259 260 /** 261 * Set the start time of this audio track relative to the storyboard 262 * timeline. Default value is 0. 263 * 264 * @param startTimeMs the start time in milliseconds 265 */ 266 public void setStartTime(long startTimeMs) { 267 mStartTimeMs = startTimeMs; 268 } 269 270 /** 271 * Get the start time of this audio track relative to the storyboard 272 * timeline. 273 * 274 * @return The start time in milliseconds 275 */ 276 public long getStartTime() { 277 return mStartTimeMs; 278 } 279 280 /** 281 * @return The duration in milliseconds. This value represents the audio 282 * track duration (not looped) 283 */ 284 public long getDuration() { 285 return mDurationMs; 286 } 287 288 /** 289 * @return The timeline duration. If looping is enabled this value 290 * represents the duration of the looped audio track, otherwise it 291 * is the duration of the audio track (mDurationMs). 292 */ 293 public long getTimelineDuration() { 294 return mTimelineDurationMs; 295 } 296 297 /** 298 * Sets the start and end marks for trimming an audio track 299 * 300 * @param beginMs start time in the audio track in milliseconds (relative to 301 * the beginning of the audio track) 302 * @param endMs end time in the audio track in milliseconds (relative to the 303 * beginning of the audio track) 304 */ 305 public void setExtractBoundaries(long beginMs, long endMs) { 306 if (beginMs > mDurationMs) { 307 throw new IllegalArgumentException("Invalid start time"); 308 } 309 if (endMs > mDurationMs) { 310 throw new IllegalArgumentException("Invalid end time"); 311 } 312 313 mBeginBoundaryTimeMs = beginMs; 314 mEndBoundaryTimeMs = endMs; 315 if (mLoop) { 316 // TODO: Compute mDurationMs (from the beginning of the loop until 317 // the end of all the loops. 318 mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs; 319 } else { 320 mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs; 321 } 322 } 323 324 /** 325 * @return The boundary begin time 326 */ 327 public long getBoundaryBeginTime() { 328 return mBeginBoundaryTimeMs; 329 } 330 331 /** 332 * @return The boundary end time 333 */ 334 public long getBoundaryEndTime() { 335 return mEndBoundaryTimeMs; 336 } 337 338 /** 339 * Enable the loop mode for this audio track. Note that only one of the 340 * audio tracks in the timeline can have the loop mode enabled. When looping 341 * is enabled the samples between mBeginBoundaryTimeMs and 342 * mEndBoundaryTimeMs are looped. 343 */ 344 public void enableLoop() { 345 mLoop = true; 346 } 347 348 /** 349 * Disable the loop mode 350 */ 351 public void disableLoop() { 352 mLoop = false; 353 } 354 355 /** 356 * @return true if looping is enabled 357 */ 358 public boolean isLooping() { 359 return mLoop; 360 } 361 362 /** 363 * Disable the audio duck effect 364 */ 365 public void disableDucking() { 366 mIsDuckingEnabled = false; 367 } 368 369 /** 370 * Enable ducking by specifying the required parameters 371 * 372 * @param threshold Ducking will be activated when the energy in 373 * the media items audio signal goes above this value. The valid 374 * range of values is 0db to 90dB. 0dB is equivalent to disabling 375 * ducking. 376 * @param duckedTrackVolume The relative volume of the audio track when ducking 377 * is active. The valid range of values is 0 to 100. 378 */ 379 public void enableDucking(int threshold, int duckedTrackVolume) { 380 if (threshold < 0 || threshold > 90) { 381 throw new IllegalArgumentException("Invalid threshold value: " + threshold); 382 } 383 384 if (duckedTrackVolume < 0 || duckedTrackVolume > 100) { 385 throw new IllegalArgumentException("Invalid duckedTrackVolume value: " 386 + duckedTrackVolume); 387 } 388 389 mDuckingThreshold = threshold; 390 mDuckedTrackVolume = duckedTrackVolume; 391 mIsDuckingEnabled = true; 392 } 393 394 /** 395 * @return true if ducking is enabled 396 */ 397 public boolean isDuckingEnabled() { 398 return mIsDuckingEnabled; 399 } 400 401 /** 402 * @return The ducking threshold 403 */ 404 public int getDuckingThreshhold() { 405 return mDuckingThreshold; 406 } 407 408 /** 409 * @return The ducked track volume 410 */ 411 public int getDuckedTrackVolume() { 412 return mDuckedTrackVolume; 413 } 414 415 /** 416 * This API allows to generate a file containing the sample volume levels of 417 * this audio track object. This function may take significant time and is 418 * blocking. The filename can be retrieved using getAudioWaveformFilename(). 419 * 420 * @param listener The progress listener 421 * 422 * @throws IOException if the output file cannot be created 423 * @throws IllegalArgumentException if the audio file does not have a valid 424 * audio track 425 */ 426 public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener) 427 throws IOException { 428 // TODO: Set mAudioWaveformFilename at the end once the extract is 429 // complete 430 mWaveformData = new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename)); 431 } 432 433 /** 434 * Get the audio waveform file name if extractAudioWaveform was successful. 435 * The file format is as following: 436 * <ul> 437 * <li>first 4 bytes provide the number of samples for each value, as 438 * big-endian signed</li> 439 * <li>4 following bytes is the total number of values in the file, as 440 * big-endian signed</li> 441 * <li>then, all values follow as bytes</li> 442 * </ul> 443 * 444 * @return the name of the file, null if the file does not exist 445 */ 446 String getAudioWaveformFilename() { 447 return mAudioWaveformFilename; 448 } 449 450 /** 451 * @return The waveform data 452 */ 453 public WaveformData getWaveformData() { 454 if (mWaveformData == null) { 455 return null; 456 } 457 458 WaveformData waveformData = mWaveformData.get(); 459 if (waveformData != null) { 460 return waveformData; 461 } else if (mAudioWaveformFilename != null) { 462 waveformData = new WaveformData(mAudioWaveformFilename); 463 mWaveformData = new SoftReference<WaveformData>(waveformData); 464 return waveformData; 465 } else { 466 return null; 467 } 468 } 469 470 /* 471 * {@inheritDoc} 472 */ 473 @Override 474 public boolean equals(Object object) { 475 if (!(object instanceof AudioTrack)) { 476 return false; 477 } 478 return mUniqueId.equals(((AudioTrack)object).mUniqueId); 479 } 480 481 /* 482 * {@inheritDoc} 483 */ 484 @Override 485 public int hashCode() { 486 return mUniqueId.hashCode(); 487 } 488} 489