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 com.android.videoeditor.service;
18
19import java.io.IOException;
20
21import android.media.videoeditor.AudioTrack;
22import android.media.videoeditor.MediaProperties;
23import android.media.videoeditor.VideoEditor;
24import android.media.videoeditor.WaveformData;
25
26/**
27 * This class represents an audio track in the user interface
28 */
29public class MovieAudioTrack {
30    // Instance variables
31    private final String mUniqueId;
32    private final String mFilename;
33    private final int mRawResourceId;
34    private final long mDurationMs;
35    private long mStartTimeMs;
36    private long mTimelineDurationMs;
37    private int mVolumePercent;
38    private boolean mMuted;
39    private long mBeginBoundaryTimeMs;
40    private long mEndBoundaryTimeMs;
41    private boolean mLoop;
42
43    private final int mAudioChannels;
44    private final int mAudioType;
45    private final int mAudioBitrate;
46    private final int mAudioSamplingFrequency;
47
48    // Ducking variables
49    private boolean mIsDuckingEnabled;
50
51    // The audio waveform data
52    private WaveformData mWaveformData;
53
54    private long mAppStartTimeMs;
55    private int mAppVolumePercent;
56    private boolean mAppMuted;
57    private boolean mAppIsDuckingEnabled;
58    private boolean mAppLoop;
59
60    /**
61     * An object of this type cannot be instantiated by using the default
62     * constructor
63     */
64    @SuppressWarnings("unused")
65    private MovieAudioTrack() throws IOException {
66        this((AudioTrack)null);
67    }
68
69    /**
70     * Constructor
71     *
72     * @param audioTrack The audio track
73     */
74    MovieAudioTrack(AudioTrack audioTrack) {
75        mUniqueId = audioTrack.getId();
76        mFilename = audioTrack.getFilename();
77        mRawResourceId = 0;
78        mAppStartTimeMs = mStartTimeMs = audioTrack.getStartTime();
79        mDurationMs = audioTrack.getDuration();
80        mBeginBoundaryTimeMs = audioTrack.getBoundaryBeginTime();
81        mEndBoundaryTimeMs = audioTrack.getBoundaryEndTime();
82
83        mAudioChannels = audioTrack.getAudioChannels();
84        mAudioType = audioTrack.getAudioType();
85        mAudioBitrate = audioTrack.getAudioBitrate();
86        mAudioSamplingFrequency = audioTrack.getAudioSamplingFrequency();
87
88        mAppVolumePercent = mVolumePercent = audioTrack.getVolume();
89        mAppMuted = mMuted = audioTrack.isMuted();
90        mAppLoop = mLoop = audioTrack.isLooping();
91
92        mAppIsDuckingEnabled = mIsDuckingEnabled = audioTrack.isDuckingEnabled();
93
94        try {
95            mWaveformData = audioTrack.getWaveformData();
96        } catch (Exception ex) {
97            mWaveformData = null;
98        }
99
100        mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
101    }
102
103    /**
104     * Constructor
105     *
106     * @param resId The audio track raw resource id
107     */
108    MovieAudioTrack(int resId) {
109        mUniqueId = null;
110        mFilename = null;
111        mRawResourceId = resId;
112        mAppStartTimeMs = mStartTimeMs = 0;
113        mDurationMs = VideoEditor.DURATION_OF_STORYBOARD;
114        mBeginBoundaryTimeMs = mStartTimeMs;
115        mEndBoundaryTimeMs = mDurationMs;
116
117        mAudioChannels = 0;
118        mAudioType = MediaProperties.ACODEC_AAC_LC;
119        mAudioBitrate = 0;
120        mAudioSamplingFrequency = 0;
121
122        mAppVolumePercent = mVolumePercent = 100;
123        mAppMuted = mMuted = false;
124        mAppLoop = mLoop = true;
125
126        mAppIsDuckingEnabled = mIsDuckingEnabled = true;
127
128        mWaveformData = null;
129
130        mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
131    }
132
133    /**
134     * @return The id of the media item
135     */
136    public String getId() {
137        return mUniqueId;
138    }
139
140    /**
141     * @return The raw resource id
142     */
143    public int getRawResourceId() {
144        return mRawResourceId;
145    }
146
147    /**
148     * Get the filename source for this audio track.
149     *
150     * @return The filename as an absolute file name
151     */
152    public String getFilename() {
153        return mFilename;
154    }
155
156    /**
157     * @return The number of audio channels in the source of this audio track
158     */
159    public int getAudioChannels() {
160        return mAudioChannels;
161    }
162
163    /**
164     * @return The audio codec of the source of this audio track
165     */
166    public int getAudioType() {
167        return mAudioType;
168    }
169
170    /**
171     * @return The audio sample frequency of the audio track
172     */
173    public int getAudioSamplingFrequency() {
174        return mAudioSamplingFrequency;
175    }
176
177    /**
178     * @return The audio bitrate of the audio track
179     */
180    public int getAudioBitrate() {
181        return mAudioBitrate;
182    }
183
184    /**
185     * Set the volume of this audio track as percentage of the volume in the
186     * original audio source file.
187     *
188     * @param volumePercent Percentage of the volume to apply. If it is set to
189     *            0, then volume becomes mute. It it is set to 100, then volume
190     *            is same as original volume. It it is set to 200, then volume
191     *            is doubled (provided that volume amplification is supported)
192     * @throws UnsupportedOperationException if volume amplification is requested
193     *             and is not supported.
194     */
195    void setVolume(int volumePercent) {
196        mVolumePercent = volumePercent;
197    }
198
199    /**
200     * Get the volume of the audio track as percentage of the volume in the
201     * original audio source file.
202     *
203     * @return The volume in percentage
204     */
205    int getVolume() {
206        return mVolumePercent;
207    }
208
209    /**
210     * Set the volume of this audio track as percentage of the volume in the
211     * original audio source file.
212     *
213     * @param volumePercent Percentage of the volume to apply. If it is set to
214     *            0, then volume becomes mute. It it is set to 100, then volume
215     *            is same as original volume. It it is set to 200, then volume
216     *            is doubled (provided that volume amplification is supported)
217     * @throws UnsupportedOperationException if volume amplification is requested
218     *             and is not supported.
219     */
220    public void setAppVolume(int volumePercent) {
221        mAppVolumePercent = volumePercent;
222    }
223
224    /**
225     * Get the volume of the audio track as percentage of the volume in the
226     * original audio source file.
227     *
228     * @return The volume in percentage
229     */
230    public int getAppVolume() {
231        return mAppVolumePercent;
232    }
233
234    /**
235     * @param muted true to mute the audio track
236     */
237    void setMute(boolean muted) {
238        mMuted = muted;
239    }
240
241    /**
242     * @return true if the audio track is muted
243     */
244    boolean isMuted() {
245        return mMuted;
246    }
247
248    /**
249     * @param muted true to mute the audio track
250     */
251    public void setAppMute(boolean muted) {
252        mAppMuted = muted;
253    }
254
255    /**
256     * @return true if the audio track is muted
257     */
258    public boolean isAppMuted() {
259        return mAppMuted;
260    }
261
262    /**
263     * Set the start time of this audio track relative to the storyboard
264     * timeline. Default value is 0.
265     *
266     * @param startTimeMs the start time in milliseconds
267     */
268    void setStartTime(long startTimeMs) {
269        mStartTimeMs = startTimeMs;
270    }
271
272    /**
273     * Get the start time of this audio track relative to the storyboard
274     * timeline.
275     *
276     * @return The start time in milliseconds
277     */
278    public long getStartTime() {
279        return mStartTimeMs;
280    }
281
282    /**
283     * Set the start time of this audio track relative to the storyboard
284     * timeline. Default value is 0.
285     *
286     * @param startTimeMs the start time in milliseconds
287     */
288    public void setAppStartTime(long startTimeMs) {
289        mAppStartTimeMs = startTimeMs;
290    }
291
292    /**
293     * Get the start time of this audio track relative to the storyboard
294     * timeline.
295     *
296     * @return The start time in milliseconds
297     */
298    public long getAppStartTime() {
299        return mAppStartTimeMs;
300    }
301
302    /**
303     * @return The duration in milliseconds. This value represents the audio
304     *         track duration (not looped)
305     */
306    public long getDuration() {
307        return mDurationMs;
308    }
309
310    /**
311     * @return The timeline duration.
312     */
313    public long getTimelineDuration() {
314        return mTimelineDurationMs;
315    }
316
317    /**
318     * Sets the start and end marks for trimming an audio track
319     *
320     * @param beginMs start time in the audio track in milliseconds (relative to
321     *            the beginning of the audio track)
322     * @param endMs end time in the audio track in milliseconds (relative to the
323     *            beginning of the audio track)
324     */
325    void setExtractBoundaries(long beginMs, long endMs) {
326        mBeginBoundaryTimeMs = beginMs;
327        mEndBoundaryTimeMs = endMs;
328        mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
329    }
330
331    /**
332     * @return The boundary begin time
333     */
334    public long getBoundaryBeginTime() {
335        return mBeginBoundaryTimeMs;
336    }
337
338    /**
339     * @return The boundary end time
340     */
341    public long getBoundaryEndTime() {
342        return mEndBoundaryTimeMs;
343    }
344
345    /**
346     * Enable the loop mode for this audio track. Note that only one of the
347     * audio tracks in the timeline can have the loop mode enabled. When looping
348     * is enabled the samples between mBeginBoundaryTimeMs and
349     * mEndBoundaryTimeMs are looped.
350     *
351     * @param loop true to enable looping
352     */
353    void enableLoop(boolean loop) {
354        mLoop = loop;
355    }
356
357    /**
358     * @return true if looping is enabled
359     */
360    boolean isLooping() {
361        return mLoop;
362    }
363
364    /**
365     * Enable the loop mode for this audio track. Note that only one of the
366     * audio tracks in the timeline can have the loop mode enabled. When looping
367     * is enabled the samples between mBeginBoundaryTimeMs and
368     * mEndBoundaryTimeMs are looped.
369     *
370     * @param loop true to enable looping
371     */
372    public void enableAppLoop(boolean loop) {
373        mAppLoop = loop;
374    }
375
376    /**
377     * @return true if looping is enabled
378     */
379    public boolean isAppLooping() {
380        return mAppLoop;
381    }
382
383    /**
384     * Enable/disable ducking
385     *
386     * @param enabled true to enable ducking
387     */
388    void enableDucking(boolean enabled) {
389        mIsDuckingEnabled = enabled;
390    }
391
392    /**
393     * @return true if ducking is enabled
394     */
395    boolean isDuckingEnabled() {
396        return mIsDuckingEnabled;
397    }
398
399    /**
400     * Enable/disable ducking
401     *
402     * @param enabled true to enable ducking
403     */
404    public void enableAppDucking(boolean enabled) {
405        mAppIsDuckingEnabled = enabled;
406    }
407
408    /**
409     * @return true if ducking is enabled
410     */
411    public boolean isAppDuckingEnabled() {
412        return mAppIsDuckingEnabled;
413    }
414
415    /**
416     * @return The waveform data
417     */
418    public WaveformData getWaveformData() {
419        return mWaveformData;
420    }
421
422    /**
423     * @param waveformData The audio waveform data
424     */
425    void setWaveformData(WaveformData waveformData) {
426        mWaveformData = waveformData;
427    }
428
429    /*
430     * {@inheritDoc}
431     */
432    @Override
433    public boolean equals(Object object) {
434        if (!(object instanceof MovieAudioTrack)) {
435            return false;
436        }
437        return mUniqueId.equals(((MovieAudioTrack)object).mUniqueId);
438    }
439
440    /*
441     * {@inheritDoc}
442     */
443    @Override
444    public int hashCode() {
445        return mUniqueId.hashCode();
446    }
447}
448