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