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