VideoEditorAudioPlayer.cpp revision 643290dc4c83da23b1b8ff4ed71118203274bb15
1/*
2 * Copyright (C) 2011 NXP Software
3 * Copyright (C) 2011 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_NDEBUG 1
19#define LOG_TAG "VideoEditorAudioPlayer"
20#include <utils/Log.h>
21
22#include <binder/IPCThreadState.h>
23#include <media/AudioTrack.h>
24#include <VideoEditorAudioPlayer.h>
25#include <media/stagefright/MediaDebug.h>
26#include <media/stagefright/MediaDefs.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaSource.h>
29#include <media/stagefright/MetaData.h>
30
31#include "PreviewPlayer.h"
32namespace android {
33
34VideoEditorAudioPlayer::VideoEditorAudioPlayer(
35        const sp<MediaPlayerBase::AudioSink> &audioSink,
36        AwesomePlayer *observer)
37    : AudioPlayer(audioSink, observer) {
38
39    LOGV("VideoEditorAudioPlayer");
40    mBGAudioPCMFileHandle = NULL;
41    mBGAudioPCMFileLength = 0;
42    mBGAudioPCMFileTrimmedLength = 0;
43    mBGAudioPCMFileDuration = 0;
44    mBGAudioPCMFileSeekPoint = 0;
45    mBGAudioPCMFileOriginalSeekPoint = 0;
46    mBGAudioStoryBoardSkimTimeStamp = 0;
47    mBGAudioStoryBoardCurrentMediaBeginCutTS = 0;
48    mBGAudioStoryBoardCurrentMediaVolumeVal = 0;
49    mSeekTimeUs = 0;
50}
51
52VideoEditorAudioPlayer::~VideoEditorAudioPlayer() {
53
54    LOGV("~VideoEditorAudioPlayer");
55    if (mStarted) {
56        reset();
57    }
58}
59
60status_t VideoEditorAudioPlayer::start(bool sourceAlreadyStarted) {
61
62    CHECK(!mStarted);
63    CHECK(mSource != NULL);
64    LOGV("Start");
65    status_t err;
66    M4OSA_ERR result = M4NO_ERROR;
67    M4OSA_UInt32 startTime = 0;
68    M4OSA_UInt32 seekTimeStamp = 0;
69    M4OSA_Bool bStoryBoardTSBeyondBTEndCutTime = M4OSA_FALSE;
70
71    if (!sourceAlreadyStarted) {
72        err = mSource->start();
73        if (err != OK) {
74            return err;
75        }
76    }
77
78    // Create the BG Audio handler
79    mAudioProcess = new VideoEditorBGAudioProcessing();
80    veAudMixSettings audioMixSettings;
81
82    // Pass on the audio ducking parameters
83    audioMixSettings.lvInDucking_threshold = mAudioMixSettings->uiInDucking_threshold;
84    audioMixSettings.lvInDucking_lowVolume = ((M4OSA_Float)mAudioMixSettings->uiInDucking_lowVolume) / 100.0;
85    audioMixSettings.lvInDucking_enable = mAudioMixSettings->bInDucking_enable;
86    audioMixSettings.lvPTVolLevel = ((M4OSA_Float)mBGAudioStoryBoardCurrentMediaVolumeVal) / 100.0;
87    audioMixSettings.lvBTVolLevel = ((M4OSA_Float)mAudioMixSettings->uiAddVolume) /100.0;
88    audioMixSettings.lvBTChannelCount = mAudioMixSettings->uiBTChannelCount;
89    audioMixSettings.lvPTChannelCount = mAudioMixSettings->uiNbChannels;
90
91    // Call to Audio mix param setting
92    mAudioProcess->veSetAudioProcessingParams(audioMixSettings);
93
94    // Get the BG Audio PCM file details
95    if ( mBGAudioPCMFileHandle ) {
96
97        // TODO : 32bits required for OSAL, to be updated once OSAL is updated
98        M4OSA_UInt32 tmp32 = 0;
99        result = M4OSA_fileReadGetOption(mBGAudioPCMFileHandle,
100                                        M4OSA_kFileReadGetFileSize,
101                                        (M4OSA_Void**)&tmp32);
102        mBGAudioPCMFileLength = tmp32;
103        mBGAudioPCMFileTrimmedLength = mBGAudioPCMFileLength;
104
105
106        LOGV("VideoEditorAudioPlayer::start M4OSA_kFileReadGetFileSize = %lld",
107                            mBGAudioPCMFileLength);
108
109        // Get the duration in time of the audio BT
110        if ( result == M4NO_ERROR ) {
111         LOGV("VEAP: channels = %d freq = %d",
112         mAudioMixSettings->uiNbChannels,  mAudioMixSettings->uiSamplingFrequency);
113
114            // No trim
115            mBGAudioPCMFileDuration = ((
116                    (int64_t)(mBGAudioPCMFileLength/sizeof(M4OSA_UInt16)/
117                    mAudioMixSettings->uiNbChannels))*1000 ) /
118                    mAudioMixSettings->uiSamplingFrequency;
119
120            LOGV("VideoEditorAudioPlayer:: beginCutMs %d , endCutMs %d",
121                    (unsigned int) mAudioMixSettings->beginCutMs,
122                    (unsigned int) mAudioMixSettings->endCutMs);
123
124            // Remove the trim part
125            if ((mAudioMixSettings->beginCutMs == 0) &&
126                (mAudioMixSettings->endCutMs != 0)) {
127                // End time itself the file duration
128                mBGAudioPCMFileDuration = mAudioMixSettings->endCutMs;
129                // Limit the file length also
130                mBGAudioPCMFileTrimmedLength = ((
131                     (int64_t)(mBGAudioPCMFileDuration *
132                     mAudioMixSettings->uiSamplingFrequency) *
133                     mAudioMixSettings->uiNbChannels) *
134                     sizeof(M4OSA_UInt16)) / 1000;
135            }
136            else if ((mAudioMixSettings->beginCutMs != 0) &&
137                     (mAudioMixSettings->endCutMs == mBGAudioPCMFileDuration)) {
138                // End time itself the file duration
139                mBGAudioPCMFileDuration = mBGAudioPCMFileDuration -
140                      mAudioMixSettings->beginCutMs;
141                // Limit the file length also
142                mBGAudioPCMFileTrimmedLength = ((
143                     (int64_t)(mBGAudioPCMFileDuration *
144                     mAudioMixSettings->uiSamplingFrequency) *
145                     mAudioMixSettings->uiNbChannels) *
146                     sizeof(M4OSA_UInt16)) / 1000;
147            }
148            else if ((mAudioMixSettings->beginCutMs != 0) &&
149                    (mAudioMixSettings->endCutMs != 0)) {
150                // End time itself the file duration
151                mBGAudioPCMFileDuration = mAudioMixSettings->endCutMs -
152                    mAudioMixSettings->beginCutMs;
153                // Limit the file length also
154                mBGAudioPCMFileTrimmedLength = ((
155                    (int64_t)(mBGAudioPCMFileDuration *
156                    mAudioMixSettings->uiSamplingFrequency) *
157                    mAudioMixSettings->uiNbChannels) *
158                    sizeof(M4OSA_UInt16)) / 1000; /*make to sec from ms*/
159            }
160
161            LOGV("VideoEditorAudioPlayer: file duration recorded : %lld",
162                    mBGAudioPCMFileDuration);
163        }
164
165        // Last played location to be seeked at for next media item
166        if ( result == M4NO_ERROR ) {
167            LOGV("VideoEditorAudioPlayer::mBGAudioStoryBoardSkimTimeStamp %lld",
168                    mBGAudioStoryBoardSkimTimeStamp);
169            LOGV("VideoEditorAudioPlayer::uiAddCts %d",
170                    mAudioMixSettings->uiAddCts);
171            if (mBGAudioStoryBoardSkimTimeStamp >= mAudioMixSettings->uiAddCts) {
172                startTime = (mBGAudioStoryBoardSkimTimeStamp -
173                 mAudioMixSettings->uiAddCts);
174            }
175            else {
176                // do nothing
177            }
178
179            LOGV("VideoEditorAudioPlayer::startTime %d", startTime);
180            seekTimeStamp = 0;
181            if (startTime) {
182                if (startTime >= mBGAudioPCMFileDuration) {
183                    // The BG track should be looped and started again
184                    if (mAudioMixSettings->bLoop) {
185                        // Add begin cut time to the mod value
186                        seekTimeStamp = ((startTime%mBGAudioPCMFileDuration) +
187                        mAudioMixSettings->beginCutMs);
188                    }else {
189                        // Looping disabled, donot do BT Mix , set to file end
190                        seekTimeStamp = (mBGAudioPCMFileDuration +
191                        mAudioMixSettings->beginCutMs);
192                    }
193                }else {
194                    // BT still present , just seek to story board time
195                    seekTimeStamp = startTime + mAudioMixSettings->beginCutMs;
196                }
197            }
198            else {
199                seekTimeStamp = mAudioMixSettings->beginCutMs;
200            }
201
202            // Convert the seekTimeStamp to file location
203            mBGAudioPCMFileOriginalSeekPoint = (
204                                        (int64_t)(mAudioMixSettings->beginCutMs)
205                                        * mAudioMixSettings->uiSamplingFrequency
206                                        * mAudioMixSettings->uiNbChannels
207                                        * sizeof(M4OSA_UInt16))/ 1000 ; /*make to sec from ms*/
208
209            mBGAudioPCMFileSeekPoint = ((int64_t)(seekTimeStamp)
210                                        * mAudioMixSettings->uiSamplingFrequency
211                                        * mAudioMixSettings->uiNbChannels
212                                        * sizeof(M4OSA_UInt16))/ 1000 ;
213        }
214    }
215
216    // We allow an optional INFO_FORMAT_CHANGED at the very beginning
217    // of playback, if there is one, getFormat below will retrieve the
218    // updated format, if there isn't, we'll stash away the valid buffer
219    // of data to be used on the first audio callback.
220
221    CHECK(mFirstBuffer == NULL);
222
223    mFirstBufferResult = mSource->read(&mFirstBuffer);
224    if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
225        LOGV("INFO_FORMAT_CHANGED!!!");
226
227        CHECK(mFirstBuffer == NULL);
228        mFirstBufferResult = OK;
229        mIsFirstBuffer = false;
230    } else {
231        mIsFirstBuffer = true;
232    }
233
234    sp<MetaData> format = mSource->getFormat();
235    const char *mime;
236    bool success = format->findCString(kKeyMIMEType, &mime);
237    CHECK(success);
238    CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
239
240    success = format->findInt32(kKeySampleRate, &mSampleRate);
241    CHECK(success);
242
243    int32_t numChannels;
244    success = format->findInt32(kKeyChannelCount, &numChannels);
245    CHECK(success);
246
247    if (mAudioSink.get() != NULL) {
248        status_t err = mAudioSink->open(
249                mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
250                DEFAULT_AUDIOSINK_BUFFERCOUNT,
251                &VideoEditorAudioPlayer::AudioSinkCallback, this);
252        if (err != OK) {
253            if (mFirstBuffer != NULL) {
254                mFirstBuffer->release();
255                mFirstBuffer = NULL;
256            }
257
258            if (!sourceAlreadyStarted) {
259                mSource->stop();
260            }
261
262            return err;
263        }
264
265        mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
266        mFrameSize = mAudioSink->frameSize();
267
268        mAudioSink->start();
269    } else {
270        mAudioTrack = new AudioTrack(
271                AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
272                (numChannels == 2)
273                    ? AudioSystem::CHANNEL_OUT_STEREO
274                    : AudioSystem::CHANNEL_OUT_MONO,
275                0, 0, &AudioCallback, this, 0);
276
277        if ((err = mAudioTrack->initCheck()) != OK) {
278            delete mAudioTrack;
279            mAudioTrack = NULL;
280
281            if (mFirstBuffer != NULL) {
282                mFirstBuffer->release();
283                mFirstBuffer = NULL;
284            }
285
286            if (!sourceAlreadyStarted) {
287                mSource->stop();
288            }
289
290            return err;
291        }
292
293        mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
294        mFrameSize = mAudioTrack->frameSize();
295
296        mAudioTrack->start();
297    }
298
299    mStarted = true;
300
301    return OK;
302}
303
304void VideoEditorAudioPlayer::reset() {
305
306    LOGV("reset");
307    AudioPlayer::reset();
308
309    // Capture the current seek point
310    mBGAudioPCMFileSeekPoint = 0;
311    mBGAudioStoryBoardSkimTimeStamp =0;
312    mBGAudioStoryBoardCurrentMediaBeginCutTS=0;
313}
314
315size_t VideoEditorAudioPlayer::AudioSinkCallback(
316        MediaPlayerBase::AudioSink *audioSink,
317        void *buffer, size_t size, void *cookie) {
318    VideoEditorAudioPlayer *me = (VideoEditorAudioPlayer *)cookie;
319
320    return me->fillBuffer(buffer, size);
321}
322
323
324size_t VideoEditorAudioPlayer::fillBuffer(void *data, size_t size) {
325
326    if (mReachedEOS) {
327        return 0;
328    }
329
330    size_t size_done = 0;
331    size_t size_remaining = size;
332
333    M4OSA_ERR err = M4NO_ERROR;
334    M4AM_Buffer bgFrame = {NULL, 0};
335    M4AM_Buffer mixFrame = {NULL, 0};
336    M4AM_Buffer ptFrame = {NULL, 0};
337    int64_t currentSteamTS = 0;
338    int64_t startTimeForBT = 0;
339    M4OSA_Float fPTVolLevel =
340     ((M4OSA_Float)mBGAudioStoryBoardCurrentMediaVolumeVal)/100;
341    M4OSA_Int16     *pPTMdata;
342    M4OSA_UInt32     uiPCMsize = 0;
343
344    while ((size_remaining > 0)&&(err==M4NO_ERROR)) {
345        MediaSource::ReadOptions options;
346
347        {
348            Mutex::Autolock autoLock(mLock);
349            if (mSeeking) {
350                if (mIsFirstBuffer) {
351                    if (mFirstBuffer != NULL) {
352                        mFirstBuffer->release();
353                        mFirstBuffer = NULL;
354                    }
355                    mIsFirstBuffer = false;
356                }
357
358                options.setSeekTo(mSeekTimeUs);
359
360                if (mInputBuffer != NULL) {
361                    mInputBuffer->release();
362                    mInputBuffer = NULL;
363                }
364
365                mSeeking = false;
366                if (mObserver) {
367                    mObserver->postAudioSeekComplete();
368                }
369            }
370        }
371
372        if (mInputBuffer == NULL) {
373            status_t status = OK;
374
375            if (mIsFirstBuffer) {
376                mInputBuffer = mFirstBuffer;
377                mFirstBuffer = NULL;
378                status = mFirstBufferResult;
379
380                mIsFirstBuffer = false;
381            } else {
382                status = mSource->read(&mInputBuffer, &options);
383                // Data is Primary Track, mix with background track
384                // after reading same size from Background track PCM file
385                if (status == OK)
386                {
387                    // Mix only when skim point is after startTime of BT
388                    if (((mBGAudioStoryBoardSkimTimeStamp* 1000) +
389                          (mPositionTimeMediaUs - mSeekTimeUs)) >=
390                          (int64_t)(mAudioMixSettings->uiAddCts * 1000)) {
391
392                        LOGV("VideoEditorAudioPlayer::INSIDE MIXING");
393                        LOGV("Checking %lld <= %lld - %d",
394                            mBGAudioPCMFileSeekPoint-mBGAudioPCMFileOriginalSeekPoint,
395                            mBGAudioPCMFileTrimmedLength, len);
396
397
398                        M4OSA_Void* ptr;
399                        ptr = (M4OSA_Void*)((unsigned int)mInputBuffer->data() +
400                        mInputBuffer->range_offset());
401
402                        M4OSA_UInt32 len = mInputBuffer->range_length();
403                        M4OSA_Context fp = M4OSA_NULL;
404
405                        uiPCMsize = (mInputBuffer->range_length())/2;
406                        pPTMdata = (M4OSA_Int16*)(mInputBuffer->data() +
407                        mInputBuffer->range_offset());
408
409                        LOGV("mix with background malloc to do len %d", len);
410
411                        bgFrame.m_dataAddress = (M4OSA_UInt16*)M4OSA_malloc( len, 1,
412                                                       (M4OSA_Char*)"bgFrame");
413                        if (NULL == bgFrame.m_dataAddress) {
414                            LOGE("mBackgroundAudioSetting Malloc failed");
415                        }
416
417                        bgFrame.m_bufferSize = len;
418
419                        mixFrame.m_dataAddress = (M4OSA_UInt16*)M4OSA_malloc(len, 1,
420                                                    (M4OSA_Char*)"mixFrame");
421                        if (NULL == mixFrame.m_dataAddress) {
422                            LOGE("mBackgroundAudioSetting Malloc failed");
423                        }
424
425                        mixFrame.m_bufferSize = len;
426
427                        LOGV("mix with bgm with size %lld", mBGAudioPCMFileLength);
428
429                        CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime,
430                                         &mPositionTimeMediaUs));
431
432                        if (mBGAudioPCMFileSeekPoint -
433                             mBGAudioPCMFileOriginalSeekPoint <=
434                              (mBGAudioPCMFileTrimmedLength - len)) {
435
436                            LOGV("Checking mBGAudioPCMFileHandle %d",
437                                (unsigned int)mBGAudioPCMFileHandle);
438
439                            if (mBGAudioPCMFileHandle != M4OSA_NULL) {
440                                LOGV("fillBuffer seeking file to %lld",
441                                    mBGAudioPCMFileSeekPoint);
442
443                            // TODO : 32bits required for OSAL
444                                M4OSA_UInt32 tmp32 =
445                                    (M4OSA_UInt32)mBGAudioPCMFileSeekPoint;
446                                err = M4OSA_fileReadSeek(mBGAudioPCMFileHandle,
447                                                M4OSA_kFileSeekBeginning,
448                                                (M4OSA_FilePosition*)&tmp32);
449
450                                mBGAudioPCMFileSeekPoint = tmp32;
451
452                                if (err != M4NO_ERROR){
453                                    LOGE("M4OSA_fileReadSeek err %d", err);
454                                }
455
456                                err = M4OSA_fileReadData(mBGAudioPCMFileHandle,
457                                       (M4OSA_Int8*)bgFrame.m_dataAddress,
458                                       (M4OSA_UInt32*)&len);
459                                if (err == M4WAR_NO_DATA_YET ) {
460
461                                    LOGV("fillBuffer End of file reached");
462                                    err = M4NO_ERROR;
463
464                                    // We reached the end of file
465                                    // move to begin cut time equal value
466                                    if (mAudioMixSettings->bLoop) {
467                                        mBGAudioPCMFileSeekPoint =
468                                         (((int64_t)(mAudioMixSettings->beginCutMs) *
469                                          mAudioMixSettings->uiSamplingFrequency) *
470                                          mAudioMixSettings->uiNbChannels *
471                                           sizeof(M4OSA_UInt16)) / 1000;
472                                        LOGV("fillBuffer Looping \
473                                            to mBGAudioPCMFileSeekPoint %lld",
474                                            mBGAudioPCMFileSeekPoint);
475                                    }
476                                    else {
477                                            // No mixing;
478                                            // take care of volume of primary track
479                                        if (fPTVolLevel < 1.0) {
480                                            setPrimaryTrackVolume(pPTMdata,
481                                             uiPCMsize, fPTVolLevel);
482                                        }
483                                    }
484                                } else if (err != M4NO_ERROR ) {
485                                     LOGV("fileReadData for audio err %d", err);
486                                } else {
487                                    mBGAudioPCMFileSeekPoint += len;
488                                    LOGV("fillBuffer mBGAudioPCMFileSeekPoint \
489                                         %lld", mBGAudioPCMFileSeekPoint);
490
491                                    // Assign the ptr data to primary track
492                                    ptFrame.m_dataAddress = (M4OSA_UInt16*)ptr;
493                                    ptFrame.m_bufferSize = len;
494
495                                    // Call to mix and duck
496                                    mAudioProcess->veProcessAudioMixNDuck(
497                                         &ptFrame, &bgFrame, &mixFrame);
498
499                                        // Overwrite the decoded buffer
500                                    M4OSA_memcpy((M4OSA_MemAddr8)ptr,
501                                         (M4OSA_MemAddr8)mixFrame.m_dataAddress, len);
502                                }
503                            }
504                        } else if (mAudioMixSettings->bLoop){
505                            // Move to begin cut time equal value
506                            mBGAudioPCMFileSeekPoint =
507                                mBGAudioPCMFileOriginalSeekPoint;
508                        } else {
509                            // No mixing;
510                            // take care of volume level of primary track
511                            if(fPTVolLevel < 1.0) {
512                                setPrimaryTrackVolume(
513                                      pPTMdata, uiPCMsize, fPTVolLevel);
514                            }
515                        }
516                        if (bgFrame.m_dataAddress) {
517                            M4OSA_free((M4OSA_MemAddr32)bgFrame.m_dataAddress);
518                        }
519                        if (mixFrame.m_dataAddress) {
520                            M4OSA_free((M4OSA_MemAddr32)mixFrame.m_dataAddress);
521                        }
522                    } else {
523                        // No mixing;
524                        // take care of volume level of primary track
525                        if(fPTVolLevel < 1.0) {
526                            setPrimaryTrackVolume(pPTMdata, uiPCMsize,
527                                                 fPTVolLevel);
528                        }
529                    }
530                }
531            }
532
533            CHECK((status == OK && mInputBuffer != NULL)
534                   || (status != OK && mInputBuffer == NULL));
535
536            Mutex::Autolock autoLock(mLock);
537
538            if (status != OK) {
539                LOGV("fillBuffer: mSource->read returned err %d", status);
540                if (mObserver && !mReachedEOS) {
541                    mObserver->postAudioEOS();
542                }
543
544                mReachedEOS = true;
545                mFinalStatus = status;
546                break;
547            }
548
549            CHECK(mInputBuffer->meta_data()->findInt64(
550                        kKeyTime, &mPositionTimeMediaUs));
551
552            mPositionTimeRealUs =
553                ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
554                    / mSampleRate;
555
556            LOGV("buffer->size() = %d, "
557                     "mPositionTimeMediaUs=%.2f mPositionTimeRealUs=%.2f",
558                 mInputBuffer->range_length(),
559                 mPositionTimeMediaUs / 1E6, mPositionTimeRealUs / 1E6);
560        }
561
562        if (mInputBuffer->range_length() == 0) {
563            mInputBuffer->release();
564            mInputBuffer = NULL;
565
566            continue;
567        }
568
569        size_t copy = size_remaining;
570        if (copy > mInputBuffer->range_length()) {
571            copy = mInputBuffer->range_length();
572        }
573
574        memcpy((char *)data + size_done,
575           (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
576               copy);
577
578        mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
579                            mInputBuffer->range_length() - copy);
580
581        size_done += copy;
582        size_remaining -= copy;
583    }
584
585    Mutex::Autolock autoLock(mLock);
586    mNumFramesPlayed += size_done / mFrameSize;
587
588    return size_done;
589}
590
591void VideoEditorAudioPlayer::setAudioMixSettings(
592                            M4xVSS_AudioMixingSettings* pAudioMixSettings) {
593    mAudioMixSettings = pAudioMixSettings;
594}
595
596void VideoEditorAudioPlayer::setAudioMixPCMFileHandle(
597                            M4OSA_Context pBGAudioPCMFileHandle){
598    mBGAudioPCMFileHandle = pBGAudioPCMFileHandle;
599}
600
601void VideoEditorAudioPlayer::setAudioMixStoryBoardSkimTimeStamp(
602                            M4OSA_UInt32 pBGAudioStoryBoardSkimTimeStamp,
603                            M4OSA_UInt32 pBGAudioCurrentMediaBeginCutTS,
604                            M4OSA_UInt32 pBGAudioCurrentMediaVolumeVal) {
605
606    mBGAudioStoryBoardSkimTimeStamp = pBGAudioStoryBoardSkimTimeStamp;
607    mBGAudioStoryBoardCurrentMediaBeginCutTS = pBGAudioCurrentMediaBeginCutTS;
608    mBGAudioStoryBoardCurrentMediaVolumeVal = pBGAudioCurrentMediaVolumeVal;
609}
610
611void VideoEditorAudioPlayer::setPrimaryTrackVolume(
612    M4OSA_Int16 *data, M4OSA_UInt32 size, M4OSA_Float volLevel) {
613
614    while(size-- > 0) {
615        *data = (M4OSA_Int16)((*data)*volLevel);
616        data++;
617    }
618}
619
620}
621