tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MFMediaEngineChild.cpp (15127B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "MFMediaEngineChild.h"
      6 
      7 #include "MFMediaEngineUtils.h"
      8 #include "RemoteMediaManagerChild.h"
      9 
     10 #ifdef MOZ_WMF_CDM
     11 #  include "WMFCDMProxy.h"
     12 #endif
     13 
     14 namespace mozilla {
     15 
     16 #define CLOG(msg, ...)                                                      \
     17  MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug,                               \
     18          ("MFMediaEngineChild=%p, Id=%" PRId64 ", " msg, this, this->Id(), \
     19           ##__VA_ARGS__))
     20 
     21 #define WLOG(msg, ...)                                                        \
     22  MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug,                                 \
     23          ("MFMediaEngineWrapper=%p, Id=%" PRId64 ", " msg, this, this->Id(), \
     24           ##__VA_ARGS__))
     25 
     26 #define WLOGV(msg, ...)                                                       \
     27  MOZ_LOG(gMFMediaEngineLog, LogLevel::Verbose,                               \
     28          ("MFMediaEngineWrapper=%p, Id=%" PRId64 ", " msg, this, this->Id(), \
     29           ##__VA_ARGS__))
     30 
     31 using media::TimeUnit;
     32 
     33 MFMediaEngineChild::MFMediaEngineChild(MFMediaEngineWrapper* aOwner,
     34                                       FrameStatistics* aFrameStats)
     35    : mOwner(aOwner),
     36      mManagerThread(RemoteMediaManagerChild::GetManagerThread()),
     37      mMediaEngineId(0 /* invalid id, will be initialized later */),
     38      mFrameStats(WrapNotNull(aFrameStats)) {
     39  if (mFrameStats->GetPresentedFrames() > 0) {
     40    mAccumulatedPresentedFramesFromPrevEngine =
     41        Some(mFrameStats->GetPresentedFrames());
     42  }
     43  if (mFrameStats->GetDroppedSinkFrames() > 0) {
     44    mAccumulatedDroppedFramesFromPrevEngine =
     45        Some(mFrameStats->GetDroppedSinkFrames());
     46  }
     47 }
     48 
     49 RefPtr<GenericNonExclusivePromise> MFMediaEngineChild::Init(
     50    const MediaInfo& aInfo, const ExternalPlaybackEngine::InitFlagSet& aFlags) {
     51  if (!mManagerThread) {
     52    return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
     53                                                       __func__);
     54  }
     55 
     56  CLOG("Init, hasAudio=%d, hasVideo=%d, encrypted=%d", aInfo.HasAudio(),
     57       aInfo.HasVideo(), aInfo.IsEncrypted());
     58 
     59  MOZ_ASSERT(mMediaEngineId == 0);
     60  RefPtr<MFMediaEngineChild> self = this;
     61  RemoteMediaManagerChild::LaunchUtilityProcessIfNeeded(
     62      RemoteMediaIn::UtilityProcess_MFMediaEngineCDM)
     63      ->Then(
     64          mManagerThread, __func__,
     65          [self, this, flag = aFlags, info = aInfo](bool) {
     66            RefPtr<RemoteMediaManagerChild> manager =
     67                RemoteMediaManagerChild::GetSingleton(
     68                    RemoteMediaIn::UtilityProcess_MFMediaEngineCDM);
     69            if (!manager || !manager->CanSend()) {
     70              CLOG("Manager not exists or can't send");
     71              mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
     72              return;
     73            }
     74 
     75            mIPDLSelfRef = this;
     76            (void)manager->SendPMFMediaEngineConstructor(this);
     77 
     78            MediaInfoIPDL mediaInfo(
     79                info.HasAudio() ? Some(info.mAudio) : Nothing(),
     80                info.HasVideo() ? Some(info.mVideo) : Nothing());
     81 
     82            MediaEngineInfoIPDL initInfo(
     83                mediaInfo,
     84                flag.contains(ExternalPlaybackEngine::InitFlag::ShouldPreload),
     85                flag.contains(
     86                    ExternalPlaybackEngine::InitFlag::EncryptedCustomIdent));
     87            SendInitMediaEngine(initInfo)
     88                ->Then(
     89                    mManagerThread, __func__,
     90                    [self, this](uint64_t aId) {
     91                      mInitEngineRequest.Complete();
     92                      // Id 0 is used to indicate error.
     93                      if (aId == 0) {
     94                        CLOG("Failed to initialize MFMediaEngineChild");
     95                        mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE,
     96                                                          __func__);
     97                        return;
     98                      }
     99                      mMediaEngineId = aId;
    100                      CLOG("Initialized MFMediaEngineChild");
    101                      mInitPromiseHolder.ResolveIfExists(true, __func__);
    102                    },
    103                    [self,
    104                     this](const mozilla::ipc::ResponseRejectReason& aReason) {
    105                      mInitEngineRequest.Complete();
    106                      CLOG(
    107                          "Failed to initialize MFMediaEngineChild due to "
    108                          "IPC failure");
    109                      mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE,
    110                                                        __func__);
    111                    })
    112                ->Track(mInitEngineRequest);
    113          },
    114          [self, this](nsresult aResult) {
    115            CLOG("SendInitMediaEngine Failed");
    116            self->mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
    117          });
    118  return mInitPromiseHolder.Ensure(__func__);
    119 }
    120 
    121 mozilla::ipc::IPCResult MFMediaEngineChild::RecvRequestSample(TrackType aType,
    122                                                              bool aIsEnough) {
    123  AssertOnManagerThread();
    124  if (!mOwner || mShutdown) {
    125    return IPC_OK();
    126  }
    127  if (aType == TrackType::kVideoTrack) {
    128    mOwner->NotifyEvent(aIsEnough ? ExternalEngineEvent::VideoEnough
    129                                  : ExternalEngineEvent::RequestForVideo);
    130  } else if (aType == TrackType::kAudioTrack) {
    131    mOwner->NotifyEvent(aIsEnough ? ExternalEngineEvent::AudioEnough
    132                                  : ExternalEngineEvent::RequestForAudio);
    133  }
    134  return IPC_OK();
    135 }
    136 
    137 mozilla::ipc::IPCResult MFMediaEngineChild::RecvUpdateCurrentTime(
    138    double aCurrentTimeInSecond) {
    139  AssertOnManagerThread();
    140  if (mShutdown) {
    141    return IPC_OK();
    142  }
    143  if (mOwner) {
    144    mOwner->UpdateCurrentTime(aCurrentTimeInSecond);
    145  }
    146  return IPC_OK();
    147 }
    148 
    149 mozilla::ipc::IPCResult MFMediaEngineChild::RecvNotifyEvent(
    150    MFMediaEngineEvent aEvent) {
    151  AssertOnManagerThread();
    152  if (mShutdown) {
    153    return IPC_OK();
    154  }
    155  switch (aEvent) {
    156    case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY:
    157      mOwner->NotifyEvent(ExternalEngineEvent::LoadedFirstFrame);
    158      break;
    159    case MF_MEDIA_ENGINE_EVENT_LOADEDDATA:
    160      mOwner->NotifyEvent(ExternalEngineEvent::LoadedData);
    161      break;
    162    case MF_MEDIA_ENGINE_EVENT_WAITING:
    163      mOwner->NotifyEvent(ExternalEngineEvent::Waiting);
    164      break;
    165    case MF_MEDIA_ENGINE_EVENT_SEEKED:
    166      mOwner->NotifyEvent(ExternalEngineEvent::Seeked);
    167      break;
    168    case MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED:
    169      mOwner->NotifyEvent(ExternalEngineEvent::BufferingStarted);
    170      break;
    171    case MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED:
    172      mOwner->NotifyEvent(ExternalEngineEvent::BufferingEnded);
    173      break;
    174    case MF_MEDIA_ENGINE_EVENT_ENDED:
    175      mOwner->NotifyEvent(ExternalEngineEvent::Ended);
    176      break;
    177    case MF_MEDIA_ENGINE_EVENT_PLAYING:
    178      mOwner->NotifyEvent(ExternalEngineEvent::Playing);
    179      break;
    180    default:
    181      NS_WARNING(
    182          nsPrintfCString("Unhandled event=%s", MediaEngineEventToStr(aEvent))
    183              .get());
    184      break;
    185  }
    186  return IPC_OK();
    187 }
    188 
    189 mozilla::ipc::IPCResult MFMediaEngineChild::RecvNotifyError(
    190    const MediaResult& aError) {
    191  AssertOnManagerThread();
    192  if (mShutdown) {
    193    return IPC_OK();
    194  }
    195  mOwner->NotifyError(aError);
    196  return IPC_OK();
    197 }
    198 
    199 mozilla::ipc::IPCResult MFMediaEngineChild::RecvUpdateStatisticData(
    200    const StatisticData& aData) {
    201  AssertOnManagerThread();
    202  const uint64_t currentRenderedFrames = mFrameStats->GetPresentedFrames();
    203  const uint64_t newRenderedFrames = GetUpdatedRenderedFrames(aData);
    204  // Media engine won't tell us that which stage those dropped frames happened,
    205  // so we treat all of them as the frames dropped in the a/v sync stage (sink).
    206  const uint64_t currentDroppedSinkFrames = mFrameStats->GetDroppedSinkFrames();
    207  const uint64_t newDroppedSinkFrames = GetUpdatedDroppedFrames(aData);
    208  mFrameStats->Accumulate({0, 0, newRenderedFrames - currentRenderedFrames, 0,
    209                           newDroppedSinkFrames - currentDroppedSinkFrames, 0});
    210  CLOG("Update statictis data (rendered %" PRIu64 " -> %" PRIu64
    211       ", dropped %" PRIu64 " -> %" PRIu64 ")",
    212       currentRenderedFrames, mFrameStats->GetPresentedFrames(),
    213       currentDroppedSinkFrames, mFrameStats->GetDroppedSinkFrames());
    214  MOZ_ASSERT(mFrameStats->GetPresentedFrames() >= currentRenderedFrames);
    215  MOZ_ASSERT(mFrameStats->GetDroppedSinkFrames() >= currentDroppedSinkFrames);
    216  return IPC_OK();
    217 }
    218 
    219 mozilla::ipc::IPCResult MFMediaEngineChild::RecvNotifyResizing(
    220    uint32_t aWidth, uint32_t aHeight) {
    221  AssertOnManagerThread();
    222  if (mShutdown) {
    223    return IPC_OK();
    224  }
    225  mOwner->NotifyResizing(aWidth, aHeight);
    226  return IPC_OK();
    227 }
    228 
    229 uint64_t MFMediaEngineChild::GetUpdatedRenderedFrames(
    230    const StatisticData& aData) {
    231  return mAccumulatedPresentedFramesFromPrevEngine
    232             ? (aData.renderedFrames() +
    233                *mAccumulatedPresentedFramesFromPrevEngine)
    234             : aData.renderedFrames();
    235 }
    236 
    237 uint64_t MFMediaEngineChild::GetUpdatedDroppedFrames(
    238    const StatisticData& aData) {
    239  return mAccumulatedDroppedFramesFromPrevEngine
    240             ? (aData.droppedFrames() +
    241                *mAccumulatedDroppedFramesFromPrevEngine)
    242             : aData.droppedFrames();
    243 }
    244 
    245 void MFMediaEngineChild::OwnerDestroyed() {
    246  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    247      "MFMediaEngineChild::OwnerDestroy", [self = RefPtr{this}, this] {
    248        self->mOwner = nullptr;
    249        // Ask to destroy IPDL.
    250        if (CanSend()) {
    251          MFMediaEngineChild::Send__delete__(this);
    252        }
    253      }));
    254 }
    255 
    256 void MFMediaEngineChild::IPDLActorDestroyed() {
    257  AssertOnManagerThread();
    258  if (!mShutdown) {
    259    CLOG("Destroyed actor without shutdown, remote process has crashed!");
    260    mOwner->NotifyError(NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR);
    261  }
    262  mIPDLSelfRef = nullptr;
    263 }
    264 
    265 void MFMediaEngineChild::Shutdown() {
    266  AssertOnManagerThread();
    267  if (mShutdown) {
    268    return;
    269  }
    270  SendShutdown();
    271  mInitPromiseHolder.RejectIfExists(NS_ERROR_FAILURE, __func__);
    272  mInitEngineRequest.DisconnectIfExists();
    273  mShutdown = true;
    274 }
    275 
    276 MFMediaEngineWrapper::MFMediaEngineWrapper(ExternalEngineStateMachine* aOwner,
    277                                           FrameStatistics* aFrameStats)
    278    : ExternalPlaybackEngine(aOwner),
    279      mEngine(new MFMediaEngineChild(this, aFrameStats)),
    280      mCurrentTimeInSecond(0.0) {}
    281 
    282 RefPtr<GenericNonExclusivePromise> MFMediaEngineWrapper::Init(
    283    const MediaInfo& aInfo, const InitFlagSet& aFlags) {
    284  WLOG("Init");
    285  return mEngine->Init(aInfo, aFlags);
    286 }
    287 
    288 MFMediaEngineWrapper::~MFMediaEngineWrapper() { mEngine->OwnerDestroyed(); }
    289 
    290 void MFMediaEngineWrapper::Play() {
    291  WLOG("Play");
    292  MOZ_ASSERT(IsInited());
    293  (void)ManagerThread()->Dispatch(
    294      NS_NewRunnableFunction("MFMediaEngineWrapper::Play",
    295                             [engine = mEngine] { engine->SendPlay(); }));
    296 }
    297 
    298 void MFMediaEngineWrapper::Pause() {
    299  WLOG("Pause");
    300  MOZ_ASSERT(IsInited());
    301  (void)ManagerThread()->Dispatch(
    302      NS_NewRunnableFunction("MFMediaEngineWrapper::Pause",
    303                             [engine = mEngine] { engine->SendPause(); }));
    304 }
    305 
    306 void MFMediaEngineWrapper::Seek(const TimeUnit& aTargetTime) {
    307  auto currentTimeInSecond = aTargetTime.ToSeconds();
    308  mCurrentTimeInSecond = currentTimeInSecond;
    309  WLOG("Seek to %f", currentTimeInSecond);
    310  MOZ_ASSERT(IsInited());
    311  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    312      "MFMediaEngineWrapper::Seek", [engine = mEngine, currentTimeInSecond] {
    313        engine->SendSeek(currentTimeInSecond);
    314      }));
    315 }
    316 
    317 void MFMediaEngineWrapper::Shutdown() {
    318  WLOG("Shutdown");
    319  (void)ManagerThread()->Dispatch(
    320      NS_NewRunnableFunction("MFMediaEngineWrapper::Shutdown",
    321                             [engine = mEngine] { engine->Shutdown(); }));
    322 }
    323 
    324 void MFMediaEngineWrapper::SetPlaybackRate(double aPlaybackRate) {
    325  WLOG("Set playback rate %f", aPlaybackRate);
    326  MOZ_ASSERT(IsInited());
    327  (void)ManagerThread()->Dispatch(
    328      NS_NewRunnableFunction("MFMediaEngineWrapper::SetPlaybackRate",
    329                             [engine = mEngine, aPlaybackRate] {
    330                               engine->SendSetPlaybackRate(aPlaybackRate);
    331                             }));
    332 }
    333 
    334 void MFMediaEngineWrapper::SetVolume(double aVolume) {
    335  WLOG("Set volume %f", aVolume);
    336  MOZ_ASSERT(IsInited());
    337  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    338      "MFMediaEngineWrapper::SetVolume",
    339      [engine = mEngine, aVolume] { engine->SendSetVolume(aVolume); }));
    340 }
    341 
    342 void MFMediaEngineWrapper::SetLooping(bool aLooping) {
    343  WLOG("Set looping %d", aLooping);
    344  MOZ_ASSERT(IsInited());
    345  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    346      "MFMediaEngineWrapper::SetLooping",
    347      [engine = mEngine, aLooping] { engine->SendSetLooping(aLooping); }));
    348 }
    349 
    350 void MFMediaEngineWrapper::SetPreservesPitch(bool aPreservesPitch) {
    351  // Media Engine doesn't support this.
    352 }
    353 
    354 void MFMediaEngineWrapper::NotifyEndOfStream(TrackInfo::TrackType aType) {
    355  WLOG("NotifyEndOfStream, type=%s", TrackTypeToStr(aType));
    356  MOZ_ASSERT(IsInited());
    357  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    358      "MFMediaEngineWrapper::NotifyEndOfStream",
    359      [engine = mEngine, aType] { engine->SendNotifyEndOfStream(aType); }));
    360 }
    361 
    362 bool MFMediaEngineWrapper::SetCDMProxy(CDMProxy* aProxy) {
    363 #ifdef MOZ_WMF_CDM
    364  WMFCDMProxy* proxy = aProxy->AsWMFCDMProxy();
    365  if (!proxy) {
    366    WLOG("Only WFMCDM Proxy is supported for the media engine!");
    367    return false;
    368  }
    369 
    370  const uint64_t proxyId = proxy->GetCDMProxyId();
    371  WLOG("SetCDMProxy, CDM-Id=%" PRIu64, proxyId);
    372  MOZ_ASSERT(IsInited());
    373  (void)ManagerThread()->Dispatch(NS_NewRunnableFunction(
    374      "MFMediaEngineWrapper::SetCDMProxy",
    375      [engine = mEngine, proxy = RefPtr{aProxy}, proxyId] {
    376        engine->SendSetCDMProxyId(proxyId);
    377      }));
    378  return true;
    379 #else
    380  return false;
    381 #endif
    382 }
    383 
    384 TimeUnit MFMediaEngineWrapper::GetCurrentPosition() {
    385  return TimeUnit::FromSeconds(mCurrentTimeInSecond);
    386 }
    387 
    388 void MFMediaEngineWrapper::UpdateCurrentTime(double aCurrentTimeInSecond) {
    389  AssertOnManagerThread();
    390  WLOGV("Update current time %f", aCurrentTimeInSecond);
    391  mCurrentTimeInSecond = aCurrentTimeInSecond;
    392  NotifyEvent(ExternalEngineEvent::Timeupdate);
    393 }
    394 
    395 void MFMediaEngineWrapper::NotifyEvent(ExternalEngineEvent aEvent) {
    396  AssertOnManagerThread();
    397  WLOGV("Received event %s", ExternalEngineEventToStr(aEvent));
    398  mOwner->NotifyEvent(aEvent);
    399 }
    400 
    401 void MFMediaEngineWrapper::NotifyError(const MediaResult& aError) {
    402  AssertOnManagerThread();
    403  WLOG("Received error: %s", aError.Description().get());
    404  mOwner->NotifyError(aError);
    405 }
    406 
    407 void MFMediaEngineWrapper::NotifyResizing(uint32_t aWidth, uint32_t aHeight) {
    408  AssertOnManagerThread();
    409  WLOG("Video resizing, new size [%u,%u]", aWidth, aHeight);
    410  mOwner->NotifyResizing(aWidth, aHeight);
    411 }
    412 
    413 #undef CLOG
    414 #undef WLOG
    415 #undef WLOGV
    416 
    417 }  // namespace mozilla