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