content/media/omx/AudioOffloadPlayer.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /*
     4  * Copyright (c) 2014 The Linux Foundation. All rights reserved.
     5  * Copyright (C) 2009 The Android Open Source Project
     6  *
     7  * Licensed under the Apache License, Version 2.0 (the "License");
     8  * you may not use this file except in compliance with the License.
     9  * You may obtain a copy of the License at
    10  *
    11  *      http://www.apache.org/licenses/LICENSE-2.0
    12  *
    13  * Unless required by applicable law or agreed to in writing, software
    14  * distributed under the License is distributed on an "AS IS" BASIS,
    15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  * See the License for the specific language governing permissions and
    17  * limitations under the License.
    18  */
    20 #include "AudioOffloadPlayer.h"
    21 #include "nsComponentManagerUtils.h"
    22 #include "nsITimer.h"
    23 #include "mozilla/dom/HTMLMediaElement.h"
    25 #include <binder/IPCThreadState.h>
    26 #include <stagefright/foundation/ADebug.h>
    27 #include <stagefright/foundation/ALooper.h>
    28 #include <stagefright/MediaDefs.h>
    29 #include <stagefright/MediaErrors.h>
    30 #include <stagefright/MediaSource.h>
    31 #include <stagefright/MetaData.h>
    32 #include <stagefright/Utils.h>
    33 #include <AudioTrack.h>
    34 #include <AudioSystem.h>
    35 #include <AudioParameter.h>
    36 #include <hardware/audio.h>
    38 using namespace android;
    40 namespace mozilla {
    42 #ifdef PR_LOGGING
    43 PRLogModuleInfo* gAudioOffloadPlayerLog;
    44 #define AUDIO_OFFLOAD_LOG(type, msg) \
    45   PR_LOG(gAudioOffloadPlayerLog, type, msg)
    46 #else
    47 #define AUDIO_OFFLOAD_LOG(type, msg)
    48 #endif
    50 // maximum time in paused state when offloading audio decompression.
    51 // When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
    52 static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
    54 AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxDecoder* aObserver) :
    55   mObserver(aObserver),
    56   mInputBuffer(nullptr),
    57   mSampleRate(0),
    58   mSeeking(false),
    59   mSeekDuringPause(false),
    60   mReachedEOS(false),
    61   mSeekTimeUs(0),
    62   mStartPosUs(0),
    63   mPositionTimeMediaUs(-1),
    64   mStarted(false),
    65   mPlaying(false),
    66   mIsElementVisible(true)
    67 {
    68   MOZ_ASSERT(NS_IsMainThread());
    70 #ifdef PR_LOGGING
    71   if (!gAudioOffloadPlayerLog) {
    72     gAudioOffloadPlayerLog = PR_NewLogModule("AudioOffloadPlayer");
    73   }
    74 #endif
    76   CHECK(aObserver);
    77   mSessionId = AudioSystem::newAudioSessionId();
    78   AudioSystem::acquireAudioSessionId(mSessionId);
    79   mAudioSink = new AudioOutput(mSessionId,
    80       IPCThreadState::self()->getCallingUid());
    81 }
    83 AudioOffloadPlayer::~AudioOffloadPlayer()
    84 {
    85   Reset();
    86   AudioSystem::releaseAudioSessionId(mSessionId);
    87 }
    89 void AudioOffloadPlayer::SetSource(const sp<MediaSource> &aSource)
    90 {
    91   MOZ_ASSERT(NS_IsMainThread());
    92   CHECK(!mSource.get());
    94   mSource = aSource;
    95 }
    97 status_t AudioOffloadPlayer::Start(bool aSourceAlreadyStarted)
    98 {
    99   MOZ_ASSERT(NS_IsMainThread());
   100   CHECK(!mStarted);
   101   CHECK(mSource.get());
   103   status_t err;
   104   CHECK(mAudioSink.get());
   106   if (!aSourceAlreadyStarted) {
   107     err = mSource->start();
   109     if (err != OK) {
   110       return err;
   111     }
   112   }
   114   sp<MetaData> format = mSource->getFormat();
   115   const char* mime;
   116   int avgBitRate = -1;
   117   int32_t channelMask;
   118   int32_t numChannels;
   119   int64_t durationUs = -1;
   120   audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
   121   uint32_t flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
   122   audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
   124   CHECK(format->findCString(kKeyMIMEType, &mime));
   125   CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
   126   CHECK(format->findInt32(kKeyChannelCount, &numChannels));
   127   format->findInt32(kKeyBitRate, &avgBitRate);
   128   format->findInt64(kKeyDuration, &durationUs);
   130   if(!format->findInt32(kKeyChannelMask, &channelMask)) {
   131     channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
   132   }
   134   if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
   135     AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Couldn't map mime type \"%s\" to a valid "
   136         "AudioSystem::audio_format", mime));
   137     audioFormat = AUDIO_FORMAT_INVALID;
   138   }
   140   offloadInfo.duration_us = durationUs;
   141   offloadInfo.sample_rate = mSampleRate;
   142   offloadInfo.channel_mask = channelMask;
   143   offloadInfo.format = audioFormat;
   144   offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
   145   offloadInfo.bit_rate = avgBitRate;
   146   offloadInfo.has_video = false;
   147   offloadInfo.is_streaming = false;
   149   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("isOffloadSupported: SR=%u, CM=0x%x, "
   150       "Format=0x%x, StreamType=%d, BitRate=%u, duration=%lld us, has_video=%d",
   151       offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format,
   152       offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
   153       offloadInfo.has_video));
   155   err = mAudioSink->Open(mSampleRate,
   156                          numChannels,
   157                          channelMask,
   158                          audioFormat,
   159                          &AudioOffloadPlayer::AudioSinkCallback,
   160                          this,
   161                          (audio_output_flags_t) flags,
   162                          &offloadInfo);
   163   if (err == OK) {
   164     // If the playback is offloaded to h/w we pass the
   165     // HAL some metadata information
   166     // We don't want to do this for PCM because it will be going
   167     // through the AudioFlinger mixer before reaching the hardware
   168     SendMetaDataToHal(mAudioSink, format);
   169   }
   170   mStarted = true;
   171   mPlaying = false;
   173   return err;
   174 }
   176 status_t AudioOffloadPlayer::ChangeState(MediaDecoder::PlayState aState)
   177 {
   178   MOZ_ASSERT(NS_IsMainThread());
   179   mPlayState = aState;
   181   switch (mPlayState) {
   182     case MediaDecoder::PLAY_STATE_PLAYING: {
   183       status_t err = Play();
   184       if (err != OK) {
   185         return err;
   186       }
   187       StartTimeUpdate();
   188     } break;
   190     case MediaDecoder::PLAY_STATE_SEEKING: {
   191       int64_t seekTimeUs
   192           = mObserver->GetSeekTime();
   193       SeekTo(seekTimeUs, true);
   194       mObserver->ResetSeekTime();
   195     } break;
   197     case MediaDecoder::PLAY_STATE_PAUSED:
   198     case MediaDecoder::PLAY_STATE_SHUTDOWN:
   199       // Just pause here during play state shutdown as well to stop playing
   200       // offload track immediately. Resources will be freed by MediaOmxDecoder
   201       Pause();
   202       break;
   204     case MediaDecoder::PLAY_STATE_ENDED:
   205       Pause(true);
   206       break;
   208     default:
   209       break;
   210   }
   211   return OK;
   212 }
   214 static void ResetCallback(nsITimer* aTimer, void* aClosure)
   215 {
   216   AudioOffloadPlayer* player = static_cast<AudioOffloadPlayer*>(aClosure);
   217   if (player) {
   218     player->Reset();
   219   }
   220 }
   222 void AudioOffloadPlayer::Pause(bool aPlayPendingSamples)
   223 {
   224   MOZ_ASSERT(NS_IsMainThread());
   226   if (mStarted) {
   227     CHECK(mAudioSink.get());
   228     if (aPlayPendingSamples) {
   229       mAudioSink->Stop();
   230     } else {
   231       mAudioSink->Pause();
   232     }
   233     mPlaying = false;
   234   }
   236   if (mResetTimer) {
   237     return;
   238   }
   239   mResetTimer = do_CreateInstance("@mozilla.org/timer;1");
   240   mResetTimer->InitWithFuncCallback(ResetCallback,
   241                                     this,
   242                                     OFFLOAD_PAUSE_MAX_MSECS,
   243                                     nsITimer::TYPE_ONE_SHOT);
   244 }
   246 status_t AudioOffloadPlayer::Play()
   247 {
   248   MOZ_ASSERT(NS_IsMainThread());
   250   if (mResetTimer) {
   251     mResetTimer->Cancel();
   252     mResetTimer = nullptr;
   253   }
   255   status_t err = OK;
   257   if (!mStarted) {
   258     // Last pause timed out and offloaded audio sink was reset. Start it again
   259     err = Start(false);
   260     if (err != OK) {
   261       return err;
   262     }
   263     // Seek to last play position only when there was no seek during last pause
   264     if (!mSeeking) {
   265       SeekTo(mPositionTimeMediaUs);
   266     }
   267   }
   269   if (!mPlaying) {
   270     CHECK(mAudioSink.get());
   271     err = mAudioSink->Start();
   272     if (err == OK) {
   273       mPlaying = true;
   274     }
   275   }
   277   return err;
   278 }
   280 void AudioOffloadPlayer::Reset()
   281 {
   282   if (!mStarted) {
   283     return;
   284   }
   286   CHECK(mAudioSink.get());
   288   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("reset: mPlaying=%d mReachedEOS=%d",
   289       mPlaying, mReachedEOS));
   291   mAudioSink->Stop();
   292   // If we're closing and have reached EOS, we don't want to flush
   293   // the track because if it is offloaded there could be a small
   294   // amount of residual data in the hardware buffer which we must
   295   // play to give gapless playback.
   296   // But if we're resetting when paused or before we've reached EOS
   297   // we can't be doing a gapless playback and there could be a large
   298   // amount of data queued in the hardware if the track is offloaded,
   299   // so we must flush to prevent a track switch being delayed playing
   300   // the buffered data that we don't want now
   301   if (!mPlaying || !mReachedEOS) {
   302     mAudioSink->Flush();
   303   }
   305   mAudioSink->Close();
   306   // Make sure to release any buffer we hold onto so that the
   307   // source is able to stop().
   309   if (mInputBuffer) {
   310     AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Releasing input buffer"));
   312     mInputBuffer->release();
   313     mInputBuffer = nullptr;
   314   }
   315   mSource->stop();
   317   IPCThreadState::self()->flushCommands();
   318   StopTimeUpdate();
   320   mReachedEOS = false;
   321   mStarted = false;
   322   mPlaying = false;
   323   mStartPosUs = 0;
   324 }
   326 status_t AudioOffloadPlayer::SeekTo(int64_t aTimeUs, bool aDispatchSeekEvents)
   327 {
   328   MOZ_ASSERT(NS_IsMainThread());
   329   CHECK(mAudioSink.get());
   331   android::Mutex::Autolock autoLock(mLock);
   333   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("SeekTo ( %lld )", aTimeUs));
   335   mSeeking = true;
   336   mReachedEOS = false;
   337   mPositionTimeMediaUs = -1;
   338   mSeekTimeUs = aTimeUs;
   339   mStartPosUs = aTimeUs;
   340   mDispatchSeekEvents = aDispatchSeekEvents;
   342   if (mDispatchSeekEvents) {
   343     nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   344         &MediaDecoder::SeekingStarted);
   345     NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   346   }
   348   if (mPlaying) {
   349     mAudioSink->Pause();
   350     mAudioSink->Flush();
   351     mAudioSink->Start();
   353   } else {
   354     mSeekDuringPause = true;
   356     if (mStarted) {
   357       mAudioSink->Flush();
   358     }
   360     if (mDispatchSeekEvents) {
   361       mDispatchSeekEvents = false;
   362       AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Fake seek complete during pause"));
   363       nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   364           &MediaDecoder::SeekingStopped);
   365       NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   366     }
   367   }
   369   return OK;
   370 }
   372 double AudioOffloadPlayer::GetMediaTimeSecs()
   373 {
   374   MOZ_ASSERT(NS_IsMainThread());
   375   return (static_cast<double>(GetMediaTimeUs()) /
   376       static_cast<double>(USECS_PER_S));
   377 }
   379 int64_t AudioOffloadPlayer::GetMediaTimeUs()
   380 {
   381   android::Mutex::Autolock autoLock(mLock);
   383   int64_t playPosition = 0;
   384   if (mSeeking) {
   385     return mSeekTimeUs;
   386   }
   387   if (!mStarted) {
   388     return mPositionTimeMediaUs;
   389   }
   391   playPosition = GetOutputPlayPositionUs_l();
   392   if (!mReachedEOS) {
   393     mPositionTimeMediaUs = playPosition;
   394   }
   396   return mPositionTimeMediaUs;
   397 }
   399 int64_t AudioOffloadPlayer::GetOutputPlayPositionUs_l() const
   400 {
   401   CHECK(mAudioSink.get());
   402   uint32_t playedSamples = 0;
   404   mAudioSink->GetPosition(&playedSamples);
   406   const int64_t playedUs = (static_cast<int64_t>(playedSamples) * 1000000 ) /
   407       mSampleRate;
   409   // HAL position is relative to the first buffer we sent at mStartPosUs
   410   const int64_t renderedDuration = mStartPosUs + playedUs;
   411   return renderedDuration;
   412 }
   414 void AudioOffloadPlayer::NotifyAudioEOS()
   415 {
   416   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   417       &MediaDecoder::PlaybackEnded);
   418   NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   419 }
   421 void AudioOffloadPlayer::NotifyPositionChanged()
   422 {
   423   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   424       &MediaOmxDecoder::PlaybackPositionChanged);
   425   NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   426 }
   428 void AudioOffloadPlayer::NotifyAudioTearDown()
   429 {
   430   nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   431       &MediaOmxDecoder::AudioOffloadTearDown);
   432   NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   433 }
   435 // static
   436 size_t AudioOffloadPlayer::AudioSinkCallback(AudioSink* aAudioSink,
   437                                              void* aBuffer,
   438                                              size_t aSize,
   439                                              void* aCookie,
   440                                              AudioSink::cb_event_t aEvent)
   441 {
   442   AudioOffloadPlayer* me = (AudioOffloadPlayer*) aCookie;
   444   switch (aEvent) {
   446     case AudioSink::CB_EVENT_FILL_BUFFER:
   447       AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio position changed"));
   448       me->NotifyPositionChanged();
   449       return me->FillBuffer(aBuffer, aSize);
   451     case AudioSink::CB_EVENT_STREAM_END:
   452       AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio EOS"));
   453       me->mReachedEOS = true;
   454       me->NotifyAudioEOS();
   455       break;
   457     case AudioSink::CB_EVENT_TEAR_DOWN:
   458       AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Tear down event"));
   459       me->NotifyAudioTearDown();
   460       break;
   462     default:
   463       AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Unknown event %d from audio sink",
   464           aEvent));
   465       break;
   466   }
   467   return 0;
   468 }
   470 size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize)
   471 {
   472   CHECK(mAudioSink.get());
   474   if (mReachedEOS) {
   475     return 0;
   476   }
   478   size_t sizeDone = 0;
   479   size_t sizeRemaining = aSize;
   480   while (sizeRemaining > 0) {
   481     MediaSource::ReadOptions options;
   482     bool refreshSeekTime = false;
   484     {
   485       android::Mutex::Autolock autoLock(mLock);
   487       if (mSeeking) {
   488         options.setSeekTo(mSeekTimeUs);
   489         refreshSeekTime = true;
   491         if (mInputBuffer) {
   492           mInputBuffer->release();
   493           mInputBuffer = nullptr;
   494         }
   495         mSeeking = false;
   496       }
   497     }
   499     if (!mInputBuffer) {
   501       status_t err;
   502       err = mSource->read(&mInputBuffer, &options);
   504       CHECK((!err && mInputBuffer) || (err && !mInputBuffer));
   506       android::Mutex::Autolock autoLock(mLock);
   508       if (err != OK) {
   509         AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Error while reading media source %d "
   510             "Ok to receive EOS error at end", err));
   511         if (!mReachedEOS) {
   512           // After seek there is a possible race condition if
   513           // OffloadThread is observing state_stopping_1 before
   514           // framesReady() > 0. Ensure sink stop is called
   515           // after last buffer is released. This ensures the
   516           // partial buffer is written to the driver before
   517           // stopping one is observed.The drawback is that
   518           // there will be an unnecessary call to the parser
   519           // after parser signalled EOS.
   520           if (sizeDone > 0) {
   521             AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("send Partial buffer down"));
   522             AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("skip calling stop till next"
   523                 " fillBuffer"));
   524             break;
   525           }
   526           // no more buffers to push - stop() and wait for STREAM_END
   527           // don't set mReachedEOS until stream end received
   528           mAudioSink->Stop();
   529         }
   530         break;
   531       }
   533       if(mInputBuffer->range_length() != 0) {
   534         CHECK(mInputBuffer->meta_data()->findInt64(
   535             kKeyTime, &mPositionTimeMediaUs));
   536       }
   538       if (refreshSeekTime) {
   540         if (mDispatchSeekEvents && !mSeekDuringPause) {
   541           mDispatchSeekEvents = false;
   542           AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("FillBuffer posting SEEK_COMPLETE"));
   543           nsCOMPtr<nsIRunnable> nsEvent = NS_NewRunnableMethod(mObserver,
   544               &MediaDecoder::SeekingStopped);
   545           NS_DispatchToMainThread(nsEvent, NS_DISPATCH_NORMAL);
   547         } else if (mSeekDuringPause) {
   548           // Callback is already called for seek during pause. Just reset the
   549           // flag
   550           AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Not posting seek complete as its"
   551               " already faked"));
   552           mSeekDuringPause = false;
   553         }
   555         NotifyPositionChanged();
   557         // need to adjust the mStartPosUs for offload decoding since parser
   558         // might not be able to get the exact seek time requested.
   559         mStartPosUs = mPositionTimeMediaUs;
   560         AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Adjust seek time to: %.2f",
   561             mStartPosUs / 1E6));
   563         // clear seek time with mLock locked and once we have valid
   564         // mPositionTimeMediaUs
   565         // before clearing mSeekTimeUs check if a new seek request has been
   566         // received while we were reading from the source with mLock released.
   567         if (!mSeeking) {
   568           mSeekTimeUs = 0;
   569         }
   570       }
   571     }
   573     if (mInputBuffer->range_length() == 0) {
   574       mInputBuffer->release();
   575       mInputBuffer = nullptr;
   576       continue;
   577     }
   579     size_t copy = sizeRemaining;
   580     if (copy > mInputBuffer->range_length()) {
   581       copy = mInputBuffer->range_length();
   582     }
   584     memcpy((char *)aData + sizeDone,
   585         (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
   586         copy);
   588     mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
   589         mInputBuffer->range_length() - copy);
   591     sizeDone += copy;
   592     sizeRemaining -= copy;
   593   }
   594   return sizeDone;
   595 }
   597 void AudioOffloadPlayer::SetElementVisibility(bool aIsVisible)
   598 {
   599   MOZ_ASSERT(NS_IsMainThread());
   600   mIsElementVisible = aIsVisible;
   601   if (mIsElementVisible) {
   602     AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Element is visible. Start time update"));
   603     StartTimeUpdate();
   604   }
   605 }
   607 static void TimeUpdateCallback(nsITimer* aTimer, void* aClosure)
   608 {
   609   AudioOffloadPlayer* player = static_cast<AudioOffloadPlayer*>(aClosure);
   610   player->TimeUpdate();
   611 }
   613 void AudioOffloadPlayer::TimeUpdate()
   614 {
   615   MOZ_ASSERT(NS_IsMainThread());
   616   TimeStamp now = TimeStamp::Now();
   618   // If TIMEUPDATE_MS has passed since the last fire update event fired, fire
   619   // another timeupdate event.
   620   if ((mLastFireUpdateTime.IsNull() ||
   621       now - mLastFireUpdateTime >=
   622           TimeDuration::FromMilliseconds(TIMEUPDATE_MS))) {
   623     mLastFireUpdateTime = now;
   624     NotifyPositionChanged();
   625   }
   627   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING || !mIsElementVisible) {
   628     StopTimeUpdate();
   629   }
   630 }
   632 nsresult AudioOffloadPlayer::StartTimeUpdate()
   633 {
   634   MOZ_ASSERT(NS_IsMainThread());
   635   if (mTimeUpdateTimer) {
   636     return NS_OK;
   637   }
   639   mTimeUpdateTimer = do_CreateInstance("@mozilla.org/timer;1");
   640   return mTimeUpdateTimer->InitWithFuncCallback(TimeUpdateCallback,
   641       this,
   642       TIMEUPDATE_MS,
   643       nsITimer::TYPE_REPEATING_SLACK);
   644 }
   646 nsresult AudioOffloadPlayer::StopTimeUpdate()
   647 {
   648   MOZ_ASSERT(NS_IsMainThread());
   649   if (!mTimeUpdateTimer) {
   650     return NS_OK;
   651   }
   653   nsresult rv = mTimeUpdateTimer->Cancel();
   654   mTimeUpdateTimer = nullptr;
   655   return rv;
   656 }
   658 MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
   659 {
   660   MOZ_ASSERT(NS_IsMainThread());
   661   if (mPlayState == MediaDecoder::PLAY_STATE_SEEKING) {
   662     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING;
   663   } else if (mPlayState == MediaDecoder::PLAY_STATE_ENDED) {
   664     return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
   665   } else {
   666     return MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
   667   }
   668 }
   670 void AudioOffloadPlayer::SendMetaDataToHal(sp<AudioSink>& aSink,
   671                                            const sp<MetaData>& aMeta)
   672 {
   673   int32_t sampleRate = 0;
   674   int32_t bitRate = 0;
   675   int32_t channelMask = 0;
   676   int32_t delaySamples = 0;
   677   int32_t paddingSamples = 0;
   678   CHECK(aSink.get());
   680   AudioParameter param = AudioParameter();
   682   if (aMeta->findInt32(kKeySampleRate, &sampleRate)) {
   683     param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
   684   }
   685   if (aMeta->findInt32(kKeyChannelMask, &channelMask)) {
   686     param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
   687   }
   688   if (aMeta->findInt32(kKeyBitRate, &bitRate)) {
   689     param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
   690   }
   691   if (aMeta->findInt32(kKeyEncoderDelay, &delaySamples)) {
   692     param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
   693   }
   694   if (aMeta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
   695     param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
   696   }
   698   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("SendMetaDataToHal: bitRate %d,"
   699       " sampleRate %d, chanMask %d, delaySample %d, paddingSample %d", bitRate,
   700       sampleRate, channelMask, delaySamples, paddingSamples));
   702   aSink->SetParameters(param.toString());
   703   return;
   704 }
   706 void AudioOffloadPlayer::SetVolume(double aVolume)
   707 {
   708   MOZ_ASSERT(NS_IsMainThread());
   709   CHECK(mAudioSink.get());
   710   mAudioSink->SetVolume((float) aVolume);
   711 }
   713 } // namespace mozilla

mercurial