tor-browser

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

MFMediaSource.cpp (18857B)


      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 "MFMediaSource.h"
      6 
      7 #include <mfapi.h>
      8 #include <mfidl.h>
      9 #include <stdint.h>
     10 
     11 #include "MFCDMProxy.h"
     12 #include "MFMediaEngineAudioStream.h"
     13 #include "MFMediaEngineUtils.h"
     14 #include "MFMediaEngineVideoStream.h"
     15 #include "VideoUtils.h"
     16 #include "WMF.h"
     17 #include "mozilla/StaticPrefs_media.h"
     18 #include "mozilla/TaskQueue.h"
     19 
     20 namespace mozilla {
     21 
     22 #define LOG(msg, ...)                         \
     23  MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug, \
     24          ("MFMediaSource=%p, " msg, this, ##__VA_ARGS__))
     25 
     26 using Microsoft::WRL::ComPtr;
     27 
     28 MFMediaSource::MFMediaSource()
     29    : mPresentationEnded(false), mIsAudioEnded(false), mIsVideoEnded(false) {
     30  MOZ_COUNT_CTOR(MFMediaSource);
     31  LOG("media source created");
     32 }
     33 
     34 MFMediaSource::~MFMediaSource() {
     35  // TODO : notify cdm about the last key id?
     36  MOZ_COUNT_DTOR(MFMediaSource);
     37  LOG("media source destroyed");
     38 }
     39 
     40 HRESULT MFMediaSource::RuntimeClassInitialize(
     41    const Maybe<AudioInfo>& aAudio, const Maybe<VideoInfo>& aVideo,
     42    nsISerialEventTarget* aManagerThread, bool aIsEncryptedCustomInit) {
     43  // On manager thread.
     44  MutexAutoLock lock(mMutex);
     45 
     46  static uint64_t streamId = 1;
     47 
     48  mTaskQueue = TaskQueue::Create(
     49      GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER), "MFMediaSource");
     50  mManagerThread = aManagerThread;
     51  MOZ_ASSERT(mManagerThread, "manager thread shouldn't be nullptr!");
     52 
     53  if (aAudio) {
     54    mAudioStream.Attach(MFMediaEngineAudioStream::Create(
     55        streamId++, *aAudio, aIsEncryptedCustomInit, this));
     56    if (!mAudioStream) {
     57      NS_WARNING("Failed to create audio stream");
     58      return E_FAIL;
     59    }
     60    mAudioStreamEndedListener = mAudioStream->EndedEvent().Connect(
     61        mManagerThread, this, &MFMediaSource::HandleStreamEnded);
     62  } else {
     63    mIsAudioEnded = true;
     64  }
     65 
     66  if (aVideo) {
     67    mVideoStream.Attach(MFMediaEngineVideoStream::Create(
     68        streamId++, *aVideo, aIsEncryptedCustomInit, this));
     69    if (!mVideoStream) {
     70      NS_WARNING("Failed to create video stream");
     71      return E_FAIL;
     72    }
     73    mVideoStreamEndedListener = mVideoStream->EndedEvent().Connect(
     74        mManagerThread, this, &MFMediaSource::HandleStreamEnded);
     75  } else {
     76    mIsVideoEnded = true;
     77  }
     78 
     79  RETURN_IF_FAILED(wmf::MFCreateEventQueue(&mMediaEventQueue));
     80 
     81  LOG("Initialized a media source");
     82  return S_OK;
     83 }
     84 
     85 IFACEMETHODIMP MFMediaSource::GetCharacteristics(DWORD* aCharacteristics) {
     86  // This could be run on both mf thread pool and manager thread.
     87  {
     88    MutexAutoLock lock(mMutex);
     89    if (mState == State::Shutdowned) {
     90      return MF_E_SHUTDOWN;
     91    }
     92  }
     93  // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/ne-mfidl-mfmediasource_characteristics
     94  *aCharacteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
     95  return S_OK;
     96 }
     97 
     98 IFACEMETHODIMP MFMediaSource::CreatePresentationDescriptor(
     99    IMFPresentationDescriptor** aPresentationDescriptor) {
    100  AssertOnMFThreadPool();
    101  MutexAutoLock lock(mMutex);
    102  if (mState == State::Shutdowned) {
    103    return MF_E_SHUTDOWN;
    104  }
    105 
    106  LOG("CreatePresentationDescriptor");
    107  // See steps of creating the presentation descriptor
    108  // https://docs.microsoft.com/en-us/windows/win32/medfound/writing-a-custom-media-source#creating-the-presentation-descriptor
    109  ComPtr<IMFPresentationDescriptor> presentationDescriptor;
    110  nsTArray<ComPtr<IMFStreamDescriptor>> streamDescriptors;
    111 
    112  DWORD audioDescriptorId = 0, videoDescriptorId = 0;
    113  if (mAudioStream) {
    114    ComPtr<IMFStreamDescriptor>* descriptor = streamDescriptors.AppendElement();
    115    RETURN_IF_FAILED(
    116        mAudioStream->GetStreamDescriptor(descriptor->GetAddressOf()));
    117    audioDescriptorId = mAudioStream->DescriptorId();
    118  }
    119 
    120  if (mVideoStream) {
    121    ComPtr<IMFStreamDescriptor>* descriptor = streamDescriptors.AppendElement();
    122    RETURN_IF_FAILED(
    123        mVideoStream->GetStreamDescriptor(descriptor->GetAddressOf()));
    124    videoDescriptorId = mVideoStream->DescriptorId();
    125  }
    126 
    127  const DWORD descCount = static_cast<DWORD>(streamDescriptors.Length());
    128  MOZ_ASSERT(descCount <= 2);
    129  RETURN_IF_FAILED(wmf::MFCreatePresentationDescriptor(
    130      descCount,
    131      reinterpret_cast<IMFStreamDescriptor**>(streamDescriptors.Elements()),
    132      &presentationDescriptor));
    133 
    134  // Select default streams for the presentation descriptor.
    135  for (DWORD idx = 0; idx < descCount; idx++) {
    136    ComPtr<IMFStreamDescriptor> streamDescriptor;
    137    BOOL selected;
    138    RETURN_IF_FAILED(presentationDescriptor->GetStreamDescriptorByIndex(
    139        idx, &selected, &streamDescriptor));
    140    if (selected) {
    141      continue;
    142    }
    143    RETURN_IF_FAILED(presentationDescriptor->SelectStream(idx));
    144    DWORD streamId;
    145    streamDescriptor->GetStreamIdentifier(&streamId);
    146    LOG("  Select stream (id=%lu)", streamId);
    147  }
    148 
    149  LOG("Created a presentation descriptor (a=%lu,v=%lu)", audioDescriptorId,
    150      videoDescriptorId);
    151  *aPresentationDescriptor = presentationDescriptor.Detach();
    152  return S_OK;
    153 }
    154 
    155 IFACEMETHODIMP MFMediaSource::Start(
    156    IMFPresentationDescriptor* aPresentationDescriptor,
    157    const GUID* aGuidTimeFormat, const PROPVARIANT* aStartPosition) {
    158  AssertOnMFThreadPool();
    159  MutexAutoLock lock(mMutex);
    160  if (mState == State::Shutdowned) {
    161    return MF_E_SHUTDOWN;
    162  }
    163 
    164  // See detailed steps in following documents.
    165  // https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfmediasource-start
    166  // https://docs.microsoft.com/en-us/windows/win32/medfound/writing-a-custom-media-source#starting-the-media-source
    167 
    168  // A call to Start results in a seek if the previous state was started or
    169  // paused, and the new starting position is not VT_EMPTY.
    170  const bool isSeeking =
    171      IsSeekable() && ((mState == State::Started || mState == State::Paused) &&
    172                       aStartPosition->vt != VT_EMPTY);
    173  nsAutoCString startPosition;
    174  if (aStartPosition->vt == VT_I8) {
    175    startPosition.AppendInt(aStartPosition->hVal.QuadPart);
    176  } else if (aStartPosition->vt == VT_EMPTY) {
    177    startPosition.AppendLiteral("empty");
    178  }
    179  LOG("Start, start position=%s, isSeeking=%d", startPosition.get(), isSeeking);
    180 
    181  // Ask IMFMediaStream to send stream events.
    182  DWORD streamDescCount = 0;
    183  RETURN_IF_FAILED(
    184      aPresentationDescriptor->GetStreamDescriptorCount(&streamDescCount));
    185 
    186  // TODO : should event orders be exactly same as msdn's order?
    187  for (DWORD idx = 0; idx < streamDescCount; idx++) {
    188    ComPtr<IMFStreamDescriptor> streamDescriptor;
    189    BOOL selected;
    190    RETURN_IF_FAILED(aPresentationDescriptor->GetStreamDescriptorByIndex(
    191        idx, &selected, &streamDescriptor));
    192 
    193    DWORD streamId;
    194    RETURN_IF_FAILED(streamDescriptor->GetStreamIdentifier(&streamId));
    195 
    196    ComPtr<MFMediaEngineStream> stream;
    197    if (mAudioStream && mAudioStream->DescriptorId() == streamId) {
    198      stream = mAudioStream;
    199    } else if (mVideoStream && mVideoStream->DescriptorId() == streamId) {
    200      stream = mVideoStream;
    201    }
    202    NS_ENSURE_TRUE(stream, MF_E_INVALIDREQUEST);
    203 
    204    if (selected) {
    205      RETURN_IF_FAILED(mMediaEventQueue->QueueEventParamUnk(
    206          stream->IsSelected() ? MEUpdatedStream : MENewStream, GUID_NULL, S_OK,
    207          stream.Get()));
    208      // Need to select stream first before doing other operations.
    209      stream->SetSelected(true);
    210      if (isSeeking) {
    211        RETURN_IF_FAILED(stream->Seek(aStartPosition));
    212      } else {
    213        RETURN_IF_FAILED(stream->Start(aStartPosition));
    214      }
    215    } else {
    216      stream->SetSelected(false);
    217    }
    218  }
    219 
    220  // Send source event.
    221  RETURN_IF_FAILED(QueueEvent(isSeeking ? MESourceSeeked : MESourceStarted,
    222                              GUID_NULL, S_OK, aStartPosition));
    223  mState = State::Started;
    224  mPresentationEnded = false;
    225  if (mAudioStream && mAudioStream->IsSelected()) {
    226    mIsAudioEnded = false;
    227  }
    228  if (mVideoStream && mVideoStream->IsSelected()) {
    229    mIsVideoEnded = false;
    230  }
    231  LOG("Started media source");
    232  return S_OK;
    233 }
    234 
    235 IFACEMETHODIMP MFMediaSource::Stop() {
    236  AssertOnMFThreadPool();
    237  MutexAutoLock lock(mMutex);
    238  if (mState == State::Shutdowned) {
    239    return MF_E_SHUTDOWN;
    240  }
    241 
    242  LOG("Stop");
    243  RETURN_IF_FAILED(QueueEvent(MESourceStopped, GUID_NULL, S_OK, nullptr));
    244  if (mAudioStream) {
    245    RETURN_IF_FAILED(mAudioStream->Stop());
    246  }
    247  if (mVideoStream) {
    248    RETURN_IF_FAILED(mVideoStream->Stop());
    249  }
    250 
    251  mState = State::Stopped;
    252  LOG("Stopped media source");
    253  return S_OK;
    254 }
    255 
    256 IFACEMETHODIMP MFMediaSource::Pause() {
    257  AssertOnMFThreadPool();
    258  MutexAutoLock lock(mMutex);
    259  if (mState == State::Shutdowned) {
    260    return MF_E_SHUTDOWN;
    261  }
    262  if (mState != State::Started) {
    263    return MF_E_INVALID_STATE_TRANSITION;
    264  }
    265 
    266  LOG("Pause");
    267  RETURN_IF_FAILED(QueueEvent(MESourcePaused, GUID_NULL, S_OK, nullptr));
    268  if (mAudioStream) {
    269    RETURN_IF_FAILED(mAudioStream->Pause());
    270  }
    271  if (mVideoStream) {
    272    RETURN_IF_FAILED(mVideoStream->Pause());
    273  }
    274 
    275  mState = State::Paused;
    276  LOG("Paused media source");
    277  return S_OK;
    278 }
    279 
    280 IFACEMETHODIMP MFMediaSource::Shutdown() {
    281  // Could be called on either manager thread or MF thread pool.
    282  MutexAutoLock lock(mMutex);
    283  if (mState == State::Shutdowned) {
    284    return MF_E_SHUTDOWN;
    285  }
    286 
    287  LOG("Shutdown");
    288  // After this method is called, all IMFMediaEventQueue methods return
    289  // MF_E_SHUTDOWN.
    290  RETURN_IF_FAILED(mMediaEventQueue->Shutdown());
    291  mState = State::Shutdowned;
    292 #ifdef MOZ_WMF_CDM
    293  mCDMProxy = nullptr;
    294 #endif
    295  LOG("Shutdowned media source");
    296  return S_OK;
    297 }
    298 
    299 void MFMediaSource::ShutdownTaskQueue() {
    300  AssertOnManagerThread();
    301  LOG("ShutdownTaskQueue");
    302  MutexAutoLock lock(mMutex);
    303  if (mAudioStream) {
    304    mAudioStream->Shutdown();
    305    mAudioStream = nullptr;
    306    mAudioStreamEndedListener.DisconnectIfExists();
    307  }
    308  if (mVideoStream) {
    309    mVideoStream->Shutdown();
    310    mVideoStream = nullptr;
    311    mVideoStreamEndedListener.DisconnectIfExists();
    312  }
    313  (void)mTaskQueue->BeginShutdown();
    314  mTaskQueue = nullptr;
    315 }
    316 
    317 IFACEMETHODIMP MFMediaSource::GetEvent(DWORD aFlags, IMFMediaEvent** aEvent) {
    318  MOZ_ASSERT(mMediaEventQueue);
    319  return mMediaEventQueue->GetEvent(aFlags, aEvent);
    320 }
    321 
    322 IFACEMETHODIMP MFMediaSource::BeginGetEvent(IMFAsyncCallback* aCallback,
    323                                            IUnknown* aState) {
    324  MOZ_ASSERT(mMediaEventQueue);
    325  return mMediaEventQueue->BeginGetEvent(aCallback, aState);
    326 }
    327 
    328 IFACEMETHODIMP MFMediaSource::EndGetEvent(IMFAsyncResult* aResult,
    329                                          IMFMediaEvent** aEvent) {
    330  MOZ_ASSERT(mMediaEventQueue);
    331  return mMediaEventQueue->EndGetEvent(aResult, aEvent);
    332 }
    333 
    334 IFACEMETHODIMP MFMediaSource::QueueEvent(MediaEventType aType,
    335                                         REFGUID aExtendedType, HRESULT aStatus,
    336                                         const PROPVARIANT* aValue) {
    337  MOZ_ASSERT(mMediaEventQueue);
    338  LOG("Queued event %s", MediaEventTypeToStr(aType));
    339  PROFILER_MARKER_TEXT("MFMediaSource::QueueEvent", MEDIA_PLAYBACK, {},
    340                       nsPrintfCString("%s", MediaEventTypeToStr(aType)));
    341  RETURN_IF_FAILED(mMediaEventQueue->QueueEventParamVar(aType, aExtendedType,
    342                                                        aStatus, aValue));
    343  return S_OK;
    344 }
    345 
    346 bool MFMediaSource::IsSeekable() const {
    347  // TODO : check seekable from info.
    348  return true;
    349 }
    350 
    351 void MFMediaSource::NotifyEndOfStream(TrackInfo::TrackType aType) {
    352  AssertOnManagerThread();
    353  MutexAutoLock lock(mMutex);
    354  if (mState == State::Shutdowned) {
    355    return;
    356  }
    357  if (aType == TrackInfo::TrackType::kAudioTrack) {
    358    MOZ_ASSERT(mAudioStream);
    359    mAudioStream->NotifyEndOfStream();
    360  } else if (aType == TrackInfo::TrackType::kVideoTrack) {
    361    MOZ_ASSERT(mVideoStream);
    362    mVideoStream->NotifyEndOfStream();
    363  }
    364 }
    365 
    366 void MFMediaSource::HandleStreamEnded(TrackInfo::TrackType aType) {
    367  AssertOnManagerThread();
    368  MutexAutoLock lock(mMutex);
    369  if (mState == State::Shutdowned) {
    370    return;
    371  }
    372  if (mPresentationEnded) {
    373    LOG("Presentation is ended already");
    374    RETURN_VOID_IF_FAILED(
    375        QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, nullptr));
    376    return;
    377  }
    378 
    379  LOG("Handle %s stream ended", TrackTypeToStr(aType));
    380  if (aType == TrackInfo::TrackType::kAudioTrack) {
    381    mIsAudioEnded = true;
    382  } else if (aType == TrackInfo::TrackType::kVideoTrack) {
    383    mIsVideoEnded = true;
    384  } else {
    385    MOZ_ASSERT_UNREACHABLE("Incorrect track type!");
    386  }
    387  mPresentationEnded = mIsAudioEnded && mIsVideoEnded;
    388  LOG("PresentationEnded=%d, audioEnded=%d, videoEnded=%d",
    389      !!mPresentationEnded, mIsAudioEnded, mIsVideoEnded);
    390  PROFILER_MARKER_TEXT(
    391      " MFMediaSource::HandleStreamEnded", MEDIA_PLAYBACK, {},
    392      nsPrintfCString("PresentationEnded=%d, audioEnded=%d, videoEnded=%d",
    393                      !!mPresentationEnded, mIsAudioEnded, mIsVideoEnded));
    394  if (mPresentationEnded) {
    395    RETURN_VOID_IF_FAILED(
    396        QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, nullptr));
    397  }
    398 }
    399 
    400 void MFMediaSource::SetDCompSurfaceHandle(HANDLE aDCompSurfaceHandle,
    401                                          gfx::IntSize aDisplay) {
    402  AssertOnManagerThread();
    403  MutexAutoLock lock(mMutex);
    404  if (mVideoStream) {
    405    mVideoStream->AsVideoStream()->SetDCompSurfaceHandle(aDCompSurfaceHandle,
    406                                                         aDisplay);
    407  }
    408 }
    409 
    410 IFACEMETHODIMP MFMediaSource::GetService(REFGUID aGuidService, REFIID aRiid,
    411                                         LPVOID* aResult) {
    412  if (!IsEqualGUID(aGuidService, MF_RATE_CONTROL_SERVICE)) {
    413    return MF_E_UNSUPPORTED_SERVICE;
    414  }
    415  return QueryInterface(aRiid, aResult);
    416 }
    417 
    418 IFACEMETHODIMP MFMediaSource::GetSlowestRate(MFRATE_DIRECTION aDirection,
    419                                             BOOL aSupportsThinning,
    420                                             float* aRate) {
    421  AssertOnMFThreadPool();
    422  MOZ_ASSERT(aRate);
    423  *aRate = 0.0f;
    424  {
    425    MutexAutoLock lock(mMutex);
    426    if (mState == State::Shutdowned) {
    427      return MF_E_SHUTDOWN;
    428    }
    429  }
    430  if (aDirection == MFRATE_REVERSE) {
    431    return MF_E_REVERSE_UNSUPPORTED;
    432  }
    433  return S_OK;
    434 }
    435 
    436 IFACEMETHODIMP MFMediaSource::GetFastestRate(MFRATE_DIRECTION aDirection,
    437                                             BOOL aSupportsThinning,
    438                                             float* aRate) {
    439  AssertOnMFThreadPool();
    440  MOZ_ASSERT(aRate);
    441  {
    442    MutexAutoLock lock(mMutex);
    443    if (mState == State::Shutdowned) {
    444      *aRate = 0.0f;
    445      return MF_E_SHUTDOWN;
    446    }
    447  }
    448  if (aDirection == MFRATE_REVERSE) {
    449    return MF_E_REVERSE_UNSUPPORTED;
    450  }
    451  *aRate = 16.0f;
    452  return S_OK;
    453 }
    454 
    455 IFACEMETHODIMP MFMediaSource::IsRateSupported(BOOL aSupportsThinning,
    456                                              float aNewRate,
    457                                              float* aSupportedRate) {
    458  AssertOnMFThreadPool();
    459  {
    460    MutexAutoLock lock(mMutex);
    461    if (mState == State::Shutdowned) {
    462      return MF_E_SHUTDOWN;
    463    }
    464  }
    465 
    466  if (aSupportedRate) {
    467    *aSupportedRate = 0.0f;
    468  }
    469 
    470  MFRATE_DIRECTION direction = aNewRate >= 0 ? MFRATE_FORWARD : MFRATE_REVERSE;
    471  float fastestRate = 0.0f, slowestRate = 0.0f;
    472  GetFastestRate(direction, aSupportsThinning, &fastestRate);
    473  GetSlowestRate(direction, aSupportsThinning, &slowestRate);
    474 
    475  if (aSupportsThinning) {
    476    return MF_E_THINNING_UNSUPPORTED;
    477  } else if (aNewRate < slowestRate) {
    478    return MF_E_REVERSE_UNSUPPORTED;
    479  } else if (aNewRate > fastestRate) {
    480    return MF_E_UNSUPPORTED_RATE;
    481  }
    482 
    483  if (aSupportedRate) {
    484    *aSupportedRate = aNewRate;
    485  }
    486  return S_OK;
    487 }
    488 
    489 IFACEMETHODIMP MFMediaSource::SetRate(BOOL aSupportsThinning, float aRate) {
    490  AssertOnMFThreadPool();
    491  {
    492    MutexAutoLock lock(mMutex);
    493    if (mState == State::Shutdowned) {
    494      return MF_E_SHUTDOWN;
    495    }
    496  }
    497 
    498  HRESULT hr = IsRateSupported(aSupportsThinning, aRate, &mPlaybackRate);
    499  if (FAILED(hr)) {
    500    LOG("Unsupported playback rate %f, error=%lX", aRate, hr);
    501    return hr;
    502  }
    503 
    504  PROPVARIANT varRate;
    505  varRate.vt = VT_R4;
    506  varRate.fltVal = mPlaybackRate;
    507  LOG("Set playback rate %f", mPlaybackRate);
    508  return QueueEvent(MESourceRateChanged, GUID_NULL, S_OK, &varRate);
    509 }
    510 
    511 IFACEMETHODIMP MFMediaSource::GetRate(BOOL* aSupportsThinning, float* aRate) {
    512  AssertOnMFThreadPool();
    513  {
    514    MutexAutoLock lock(mMutex);
    515    if (mState == State::Shutdowned) {
    516      return MF_E_SHUTDOWN;
    517    }
    518  }
    519  *aSupportsThinning = FALSE;
    520  *aRate = mPlaybackRate;
    521  return S_OK;
    522 }
    523 
    524 HRESULT MFMediaSource::GetInputTrustAuthority(DWORD aStreamId, REFIID aRiid,
    525                                              IUnknown** aITAOut) {
    526  // TODO : add threading assertion, not sure what thread it would be running on
    527  // now.
    528  {
    529    MutexAutoLock lock(mMutex);
    530    if (mState == State::Shutdowned) {
    531      return MF_E_SHUTDOWN;
    532    }
    533  }
    534 #ifdef MOZ_WMF_CDM
    535  if (!mCDMProxy) {
    536    return MF_E_NOT_PROTECTED;
    537  }
    538 
    539  // TODO : verify if this aStreamId is really matching our stream id or not.
    540  ComPtr<MFMediaEngineStream> stream = GetStreamByIndentifier(aStreamId);
    541  if (!stream) {
    542    return E_INVALIDARG;
    543  }
    544 
    545  if (!stream->IsEncrypted()) {
    546    return MF_E_NOT_PROTECTED;
    547  }
    548 
    549  RETURN_IF_FAILED(
    550      mCDMProxy->GetInputTrustAuthority(aStreamId, nullptr, 0, aRiid, aITAOut));
    551 #endif
    552  return S_OK;
    553 }
    554 
    555 MFMediaSource::State MFMediaSource::GetState() const {
    556  MutexAutoLock lock(mMutex);
    557  return mState;
    558 }
    559 
    560 MFMediaEngineStream* MFMediaSource::GetAudioStream() {
    561  MutexAutoLock lock(mMutex);
    562  return mAudioStream.Get();
    563 }
    564 MFMediaEngineStream* MFMediaSource::GetVideoStream() {
    565  MutexAutoLock lock(mMutex);
    566  return mVideoStream.Get();
    567 }
    568 
    569 MFMediaEngineStream* MFMediaSource::GetStreamByIndentifier(
    570    DWORD aStreamId) const {
    571  MutexAutoLock lock(mMutex);
    572  if (mAudioStream && mAudioStream->DescriptorId() == aStreamId) {
    573    return mAudioStream.Get();
    574  }
    575  if (mVideoStream && mVideoStream->DescriptorId() == aStreamId) {
    576    return mVideoStream.Get();
    577  }
    578  return nullptr;
    579 }
    580 
    581 #ifdef MOZ_WMF_CDM
    582 void MFMediaSource::SetCDMProxy(MFCDMProxy* aCDMProxy) {
    583  AssertOnManagerThread();
    584  LOG("SetCDMProxy");
    585  mCDMProxy = aCDMProxy;
    586  // TODO : ask cdm proxy to refresh trusted input
    587 }
    588 #endif
    589 
    590 bool MFMediaSource::IsEncrypted() const {
    591  MutexAutoLock lock(mMutex);
    592  return (mAudioStream && mAudioStream->IsEncrypted()) ||
    593         (mVideoStream && mVideoStream->IsEncrypted());
    594 }
    595 
    596 void MFMediaSource::AssertOnManagerThread() const {
    597  MOZ_ASSERT(mManagerThread->IsOnCurrentThread());
    598 }
    599 
    600 void MFMediaSource::AssertOnMFThreadPool() const {
    601  // We can't really assert the thread id from thread pool, because it would
    602  // change any time. So we just assert this is not the manager thread, and use
    603  // the explicit function name to indicate what thread we should run on.
    604  MOZ_ASSERT(!mManagerThread->IsOnCurrentThread());
    605 }
    606 
    607 #undef LOG
    608 
    609 }  // namespace mozilla