MediaEngineFake.cpp (21260B)
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 file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "MediaEngineFake.h" 6 7 #include "AudioSegment.h" 8 #include "FakeVideoSource.h" 9 #include "ImageContainer.h" 10 #include "MediaEnginePrefs.h" 11 #include "MediaEngineSource.h" 12 #include "MediaTrackConstraints.h" 13 #include "MediaTrackGraph.h" 14 #include "MediaTrackListener.h" 15 #include "SineWaveGenerator.h" 16 #include "Tracing.h" 17 #include "VideoSegment.h" 18 #include "mozilla/MediaManager.h" 19 #include "mozilla/SyncRunnable.h" 20 #include "mozilla/UniquePtr.h" 21 #include "nsCOMPtr.h" 22 #include "nsContentUtils.h" 23 24 #ifdef MOZ_WIDGET_ANDROID 25 # include "nsISupportsUtils.h" 26 #endif 27 28 namespace mozilla { 29 30 using namespace mozilla::gfx; 31 using dom::GetEnumString; 32 using dom::MediaSourceEnum; 33 using dom::MediaTrackCapabilities; 34 using dom::MediaTrackConstraints; 35 using dom::MediaTrackSettings; 36 using dom::VideoFacingModeEnum; 37 using dom::VideoResizeModeEnum; 38 39 #ifdef DEBUG 40 static constexpr int VIDEO_WIDTH_DEFAULT = 41 MediaEnginePrefs::DEFAULT_43_VIDEO_WIDTH / 2; 42 #else 43 static constexpr int VIDEO_WIDTH_DEFAULT = 44 MediaEnginePrefs::DEFAULT_43_VIDEO_WIDTH; 45 #endif 46 static constexpr int VIDEO_WIDTH_MAX = 4096; 47 #ifdef DEBUG 48 static constexpr int VIDEO_HEIGHT_DEFAULT = 49 MediaEnginePrefs::DEFAULT_43_VIDEO_HEIGHT / 2; 50 #else 51 static constexpr int VIDEO_HEIGHT_DEFAULT = 52 MediaEnginePrefs::DEFAULT_43_VIDEO_HEIGHT; 53 #endif 54 static constexpr int VIDEO_HEIGHT_MAX = 2160; 55 56 static nsString FakeVideoName() { 57 // For the purpose of testing we allow to change the name of the fake device 58 // by pref. 59 nsAutoString cameraNameFromPref; 60 nsresult rv; 61 auto getPref = [&]() { 62 rv = Preferences::GetString("media.getusermedia.fake-camera-name", 63 cameraNameFromPref); 64 }; 65 if (NS_IsMainThread()) { 66 getPref(); 67 } else { 68 // Here it is preferred a "hard" block, instead of "soft" block provided 69 // by sync dispatch, which allows the waiting thread to spin its event 70 // loop. The latter would allow multiple enumeration requests being 71 // processed out-of-order. 72 RefPtr runnable = NS_NewRunnableFunction(__func__, getPref); 73 SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable); 74 } 75 76 if (NS_SUCCEEDED(rv)) { 77 return std::move(cameraNameFromPref); 78 } 79 return u"Default Video Device"_ns; 80 } 81 82 /** 83 * Fake video source. 84 */ 85 class MediaEngineFakeVideoSource : public MediaEngineSource { 86 public: 87 MediaEngineFakeVideoSource(); 88 89 static already_AddRefed<MediaEngineFakeVideoSource> CreateFrom( 90 const MediaEngineFakeVideoSource* aSource); 91 92 static nsString GetGroupId(); 93 94 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, 95 const MediaEnginePrefs& aPrefs, uint64_t aWindowID, 96 const char** aOutBadConstraint) override; 97 void SetTrack(const RefPtr<MediaTrack>& aTrack, 98 const PrincipalHandle& aPrincipal) override; 99 nsresult Start() override; 100 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints, 101 const MediaEnginePrefs& aPrefs, 102 const char** aOutBadConstraint) override; 103 nsresult Stop() override; 104 nsresult Deallocate() override; 105 106 uint32_t GetBestFitnessDistance( 107 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets, 108 const MediaEnginePrefs& aPrefs) const override; 109 void GetSettings(dom::MediaTrackSettings& aOutSettings) const override; 110 111 void GetCapabilities( 112 dom::MediaTrackCapabilities& aOutCapabilities) const override; 113 114 bool IsFake() const override { return true; } 115 116 protected: 117 ~MediaEngineFakeVideoSource() { 118 mGeneratedImageListener.DisconnectIfExists(); 119 } 120 121 void OnGeneratedImage(RefPtr<layers::Image> aImage, TimeStamp aTime); 122 123 // Owning thread only. 124 RefPtr<FakeVideoSource> mCapturer; 125 MediaEventListener mGeneratedImageListener; 126 127 // Current state of this source. 128 MediaEngineSourceState mState = kReleased; 129 RefPtr<SourceMediaTrack> mTrack; 130 PrincipalHandle mPrincipalHandle = PRINCIPAL_HANDLE_NONE; 131 132 MediaEnginePrefs mOpts; 133 134 // Main thread only. 135 const RefPtr<media::Refcountable<dom::MediaTrackSettings>> mSettings; 136 }; 137 138 MediaEngineFakeVideoSource::MediaEngineFakeVideoSource() 139 : mSettings(MakeAndAddRef<media::Refcountable<MediaTrackSettings>>()) { 140 mSettings->mWidth.Construct(int32_t(VIDEO_WIDTH_DEFAULT)); 141 mSettings->mHeight.Construct(int32_t(VIDEO_HEIGHT_DEFAULT)); 142 mSettings->mFrameRate.Construct(double(MediaEnginePrefs::DEFAULT_VIDEO_FPS)); 143 mSettings->mFacingMode.Construct(NS_ConvertASCIItoUTF16( 144 dom::GetEnumString(VideoFacingModeEnum::Environment))); 145 mSettings->mResizeMode.Construct(NS_ConvertASCIItoUTF16( 146 dom::GetEnumString(dom::VideoResizeModeEnum::None))); 147 } 148 149 /*static*/ already_AddRefed<MediaEngineFakeVideoSource> 150 MediaEngineFakeVideoSource::CreateFrom( 151 const MediaEngineFakeVideoSource* aSource) { 152 auto src = MakeRefPtr<MediaEngineFakeVideoSource>(); 153 *static_cast<MediaTrackSettings*>(src->mSettings) = *aSource->mSettings; 154 src->mOpts = aSource->mOpts; 155 return src.forget(); 156 } 157 158 nsString MediaEngineFakeVideoSource::GetGroupId() { 159 return u"Fake Video Group"_ns; 160 } 161 162 uint32_t MediaEngineFakeVideoSource::GetBestFitnessDistance( 163 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets, 164 const MediaEnginePrefs& aPrefs) const { 165 AssertIsOnOwningThread(); 166 167 uint64_t distance = 0; 168 169 #ifdef MOZ_WEBRTC 170 // distance is read from first entry only 171 if (aConstraintSets.Length() >= 1) { 172 const auto* cs = aConstraintSets.ElementAt(0); 173 const auto resizeMode = MediaConstraintsHelper::GetResizeMode(*cs, aPrefs); 174 using H = MediaConstraintsHelper; 175 Maybe<nsString> facingMode = Nothing(); 176 distance += H::FitnessDistance(facingMode, cs->mFacingMode); 177 178 if (resizeMode.valueOr(dom::VideoResizeModeEnum::None) == 179 dom::VideoResizeModeEnum::None) { 180 distance += 181 H::FitnessDistance(VIDEO_WIDTH_DEFAULT, cs->mWidth) + 182 H::FitnessDistance(VIDEO_HEIGHT_DEFAULT, cs->mHeight) + 183 H::FitnessDistance(AssertedCast<double>(aPrefs.mFPS), cs->mFrameRate); 184 } else { 185 distance += H::FeasibilityDistance(VIDEO_WIDTH_DEFAULT, cs->mWidth) + 186 H::FeasibilityDistance(VIDEO_HEIGHT_DEFAULT, cs->mHeight) + 187 H::FeasibilityDistance(AssertedCast<double>(aPrefs.mFPS), 188 cs->mFrameRate); 189 } 190 } 191 #endif 192 193 return SaturatingCast<uint32_t>(distance); 194 } 195 196 void MediaEngineFakeVideoSource::GetSettings( 197 MediaTrackSettings& aOutSettings) const { 198 MOZ_ASSERT(NS_IsMainThread()); 199 aOutSettings = *mSettings; 200 } 201 202 void MediaEngineFakeVideoSource::GetCapabilities( 203 MediaTrackCapabilities& aOutCapabilities) const { 204 MOZ_ASSERT(NS_IsMainThread()); 205 206 NS_ConvertASCIItoUTF16 facingString( 207 GetEnumString(VideoFacingModeEnum::Environment)); 208 nsTArray<nsString> facing; 209 facing.AppendElement(facingString); 210 aOutCapabilities.mFacingMode.Construct(std::move(facing)); 211 212 if (mOpts.mResizeModeEnabled) { 213 nsTArray<nsString> resizeModes{ 214 NS_ConvertASCIItoUTF16(GetEnumString(dom::VideoResizeModeEnum::None)), 215 NS_ConvertASCIItoUTF16( 216 GetEnumString(dom::VideoResizeModeEnum::Crop_and_scale))}; 217 aOutCapabilities.mResizeMode.Construct(std::move(resizeModes)); 218 } 219 220 dom::ULongRange widthRange; 221 widthRange.mMax.Construct(VIDEO_WIDTH_MAX); 222 widthRange.mMin.Construct(1); 223 aOutCapabilities.mWidth.Construct(widthRange); 224 225 dom::ULongRange heightRange; 226 heightRange.mMax.Construct(VIDEO_HEIGHT_MAX); 227 heightRange.mMin.Construct(1); 228 aOutCapabilities.mHeight.Construct(heightRange); 229 230 dom::DoubleRange frameRateRange; 231 frameRateRange.mMax.Construct(double(MediaEnginePrefs::DEFAULT_VIDEO_FPS)); 232 frameRateRange.mMin.Construct(0); 233 aOutCapabilities.mFrameRate.Construct(frameRateRange); 234 } 235 236 nsresult MediaEngineFakeVideoSource::Allocate( 237 const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, 238 uint64_t aWindowID, const char** aOutBadConstraint) { 239 AssertIsOnOwningThread(); 240 241 MOZ_ASSERT(mState == kReleased); 242 243 FlattenedConstraints c(aConstraints); 244 245 // emulator debug is very, very slow; reduce load on it with smaller/slower 246 // fake video 247 mOpts = aPrefs; 248 mOpts.mWidth = aPrefs.mWidth ? aPrefs.mWidth : VIDEO_WIDTH_DEFAULT; 249 mOpts.mHeight = aPrefs.mHeight ? aPrefs.mHeight : VIDEO_HEIGHT_DEFAULT; 250 251 const auto resizeMode = MediaConstraintsHelper::GetResizeMode(c, mOpts); 252 const auto resizeModeString = resizeMode.map( 253 [](auto aRM) { return NS_ConvertASCIItoUTF16(dom::GetEnumString(aRM)); }); 254 if (resizeMode.valueOr(VideoResizeModeEnum::None) == 255 VideoResizeModeEnum::Crop_and_scale) { 256 mOpts.mWidth = c.mWidth.Get(mOpts.mWidth); 257 mOpts.mHeight = c.mHeight.Get(mOpts.mHeight); 258 mOpts.mFPS = std::min(mOpts.mFPS, SaturatingCast<int32_t>(c.mFrameRate.Get( 259 AssertedCast<double>(mOpts.mFPS)))); 260 } 261 262 mOpts.mWidth = std::clamp(mOpts.mWidth, 1, VIDEO_WIDTH_MAX); 263 mOpts.mHeight = std::clamp(mOpts.mHeight, 1, VIDEO_HEIGHT_MAX); 264 mOpts.mFPS = std::clamp(mOpts.mFPS, 0, MediaEnginePrefs::DEFAULT_VIDEO_FPS); 265 266 nsCOMPtr<nsISerialEventTarget> target = GetCurrentSerialEventTarget(); 267 mCapturer = MakeRefPtr<FakeVideoSource>(target); 268 mGeneratedImageListener = mCapturer->GeneratedImageEvent().Connect( 269 target, this, &MediaEngineFakeVideoSource::OnGeneratedImage); 270 271 NS_DispatchToMainThread(NS_NewRunnableFunction( 272 __func__, 273 [settings = mSettings, frameRate = mOpts.mFPS, width = mOpts.mWidth, 274 height = mOpts.mHeight, resizeModeString]() { 275 settings->mFrameRate.Value() = frameRate; 276 settings->mWidth.Value() = width; 277 settings->mHeight.Value() = height; 278 settings->mResizeMode.Reset(); 279 resizeModeString.apply( 280 [&](const auto& aStr) { settings->mResizeMode.Construct(aStr); }); 281 })); 282 283 mState = kAllocated; 284 return NS_OK; 285 } 286 287 nsresult MediaEngineFakeVideoSource::Deallocate() { 288 AssertIsOnOwningThread(); 289 290 MOZ_ASSERT(mState == kStopped || mState == kAllocated); 291 292 mGeneratedImageListener.Disconnect(); 293 mCapturer = nullptr; 294 if (mTrack) { 295 mTrack->End(); 296 mTrack = nullptr; 297 mPrincipalHandle = PRINCIPAL_HANDLE_NONE; 298 } 299 mState = kReleased; 300 301 return NS_OK; 302 } 303 304 void MediaEngineFakeVideoSource::SetTrack(const RefPtr<MediaTrack>& aTrack, 305 const PrincipalHandle& aPrincipal) { 306 AssertIsOnOwningThread(); 307 308 MOZ_ASSERT(mState == kAllocated); 309 MOZ_ASSERT(!mTrack); 310 MOZ_ASSERT(aTrack->AsSourceTrack()); 311 312 mTrack = aTrack->AsSourceTrack(); 313 mPrincipalHandle = aPrincipal; 314 } 315 316 nsresult MediaEngineFakeVideoSource::Start() { 317 AssertIsOnOwningThread(); 318 319 MOZ_ASSERT(mState == kAllocated || mState == kStopped); 320 MOZ_ASSERT(mTrack, "SetTrack() must happen before Start()"); 321 322 int32_t rv = mCapturer->StartCapture( 323 mOpts.mWidth, mOpts.mHeight, TimeDuration::FromSeconds(1.0 / mOpts.mFPS)); 324 if (NS_WARN_IF(rv != 0)) { 325 return NS_ERROR_FAILURE; 326 } 327 328 mState = kStarted; 329 return NS_OK; 330 } 331 332 nsresult MediaEngineFakeVideoSource::Stop() { 333 AssertIsOnOwningThread(); 334 335 if (mState == kStopped || mState == kAllocated) { 336 return NS_OK; 337 } 338 339 MOZ_ASSERT(mState == kStarted); 340 MOZ_ASSERT(mTrack); 341 342 int32_t rv = mCapturer->StopCapture(); 343 if (NS_WARN_IF(rv != 0)) { 344 return NS_ERROR_FAILURE; 345 } 346 347 mState = kStopped; 348 349 return NS_OK; 350 } 351 352 nsresult MediaEngineFakeVideoSource::Reconfigure( 353 const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, 354 const char** aOutBadConstraint) { 355 return NS_OK; 356 } 357 358 void MediaEngineFakeVideoSource::OnGeneratedImage(RefPtr<layers::Image> aImage, 359 TimeStamp aTime) { 360 VideoSegment segment; 361 segment.AppendFrame(aImage.forget(), 362 gfx::IntSize(mOpts.mWidth, mOpts.mHeight), 363 mPrincipalHandle, /*aForceBlack=*/false, aTime); 364 mTrack->AppendData(&segment); 365 } 366 367 // This class is created on the media thread, as part of Start(), then entirely 368 // self-sustained until destruction, just forwarding calls to Pull(). 369 class AudioSourcePullListener : public MediaTrackListener { 370 public: 371 AudioSourcePullListener(RefPtr<SourceMediaTrack> aTrack, 372 const PrincipalHandle& aPrincipalHandle, 373 uint32_t aFrequency) 374 : mTrack(std::move(aTrack)), 375 mPrincipalHandle(aPrincipalHandle), 376 mSineGenerator(MakeUnique<SineWaveGenerator<int16_t>>( 377 mTrack->mSampleRate, aFrequency)) { 378 MOZ_COUNT_CTOR(AudioSourcePullListener); 379 } 380 381 MOZ_COUNTED_DTOR(AudioSourcePullListener) 382 383 void NotifyPull(MediaTrackGraph* aGraph, TrackTime aEndOfAppendedData, 384 TrackTime aDesiredTime) override; 385 386 const RefPtr<SourceMediaTrack> mTrack; 387 const PrincipalHandle mPrincipalHandle; 388 const UniquePtr<SineWaveGenerator<int16_t>> mSineGenerator; 389 }; 390 391 /** 392 * Fake audio source. 393 */ 394 class MediaEngineFakeAudioSource : public MediaEngineSource { 395 public: 396 MediaEngineFakeAudioSource() = default; 397 398 static nsString GetUUID(); 399 static nsString GetGroupId(); 400 401 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, 402 const MediaEnginePrefs& aPrefs, uint64_t aWindowID, 403 const char** aOutBadConstraint) override; 404 void SetTrack(const RefPtr<MediaTrack>& aTrack, 405 const PrincipalHandle& aPrincipal) override; 406 nsresult Start() override; 407 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints, 408 const MediaEnginePrefs& aPrefs, 409 const char** aOutBadConstraint) override; 410 nsresult Stop() override; 411 nsresult Deallocate() override; 412 413 bool IsFake() const override { return true; } 414 415 void GetSettings(dom::MediaTrackSettings& aOutSettings) const override; 416 417 void GetCapabilities( 418 dom::MediaTrackCapabilities& aOutCapabilities) const override; 419 420 protected: 421 ~MediaEngineFakeAudioSource() = default; 422 423 // Current state of this source. 424 MediaEngineSourceState mState = kReleased; 425 RefPtr<SourceMediaTrack> mTrack; 426 PrincipalHandle mPrincipalHandle = PRINCIPAL_HANDLE_NONE; 427 uint32_t mFrequency = 1000; 428 RefPtr<AudioSourcePullListener> mPullListener; 429 }; 430 431 nsString MediaEngineFakeAudioSource::GetUUID() { 432 return u"B7CBD7C1-53EF-42F9-8353-73F61C70C092"_ns; 433 } 434 435 nsString MediaEngineFakeAudioSource::GetGroupId() { 436 return u"Fake Audio Group"_ns; 437 } 438 439 void MediaEngineFakeAudioSource::GetSettings( 440 MediaTrackSettings& aOutSettings) const { 441 MOZ_ASSERT(NS_IsMainThread()); 442 aOutSettings.mAutoGainControl.Construct(false); 443 aOutSettings.mEchoCancellation.Construct(false); 444 aOutSettings.mNoiseSuppression.Construct(false); 445 aOutSettings.mChannelCount.Construct(1); 446 } 447 448 void MediaEngineFakeAudioSource::GetCapabilities( 449 MediaTrackCapabilities& aOutCapabilities) const { 450 MOZ_ASSERT(NS_IsMainThread()); 451 nsTArray<bool> echoCancellation; 452 echoCancellation.AppendElement(false); 453 aOutCapabilities.mEchoCancellation.Construct(std::move(echoCancellation)); 454 455 nsTArray<bool> autoGainControl; 456 autoGainControl.AppendElement(false); 457 aOutCapabilities.mAutoGainControl.Construct(std::move(autoGainControl)); 458 459 nsTArray<bool> noiseSuppression; 460 noiseSuppression.AppendElement(false); 461 aOutCapabilities.mNoiseSuppression.Construct(std::move(noiseSuppression)); 462 463 dom::ULongRange channelCountRange; 464 channelCountRange.mMax.Construct(1); 465 channelCountRange.mMin.Construct(1); 466 aOutCapabilities.mChannelCount.Construct(channelCountRange); 467 } 468 469 nsresult MediaEngineFakeAudioSource::Allocate( 470 const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, 471 uint64_t aWindowID, const char** aOutBadConstraint) { 472 AssertIsOnOwningThread(); 473 474 MOZ_ASSERT(mState == kReleased); 475 476 mFrequency = aPrefs.mFreq ? aPrefs.mFreq : 1000; 477 478 mState = kAllocated; 479 return NS_OK; 480 } 481 482 nsresult MediaEngineFakeAudioSource::Deallocate() { 483 AssertIsOnOwningThread(); 484 485 MOZ_ASSERT(mState == kStopped || mState == kAllocated); 486 487 if (mTrack) { 488 mTrack->End(); 489 mTrack = nullptr; 490 mPrincipalHandle = PRINCIPAL_HANDLE_NONE; 491 } 492 mState = kReleased; 493 return NS_OK; 494 } 495 496 void MediaEngineFakeAudioSource::SetTrack(const RefPtr<MediaTrack>& aTrack, 497 const PrincipalHandle& aPrincipal) { 498 AssertIsOnOwningThread(); 499 500 MOZ_ASSERT(mState == kAllocated); 501 MOZ_ASSERT(!mTrack); 502 MOZ_ASSERT(aTrack->AsSourceTrack()); 503 504 mTrack = aTrack->AsSourceTrack(); 505 mPrincipalHandle = aPrincipal; 506 } 507 508 nsresult MediaEngineFakeAudioSource::Start() { 509 AssertIsOnOwningThread(); 510 511 if (mState == kStarted) { 512 return NS_OK; 513 } 514 515 MOZ_ASSERT(mState == kAllocated || mState == kStopped); 516 MOZ_ASSERT(mTrack, "SetTrack() must happen before Start()"); 517 518 if (!mPullListener) { 519 mPullListener = MakeAndAddRef<AudioSourcePullListener>( 520 mTrack, mPrincipalHandle, mFrequency); 521 } 522 523 mState = kStarted; 524 525 NS_DispatchToMainThread(NS_NewRunnableFunction( 526 __func__, [track = mTrack, listener = mPullListener]() { 527 if (track->IsDestroyed()) { 528 return; 529 } 530 track->AddListener(listener); 531 track->SetPullingEnabled(true); 532 })); 533 534 return NS_OK; 535 } 536 537 nsresult MediaEngineFakeAudioSource::Stop() { 538 AssertIsOnOwningThread(); 539 540 if (mState == kStopped || mState == kAllocated) { 541 return NS_OK; 542 } 543 MOZ_ASSERT(mState == kStarted); 544 mState = kStopped; 545 546 NS_DispatchToMainThread(NS_NewRunnableFunction( 547 __func__, [track = mTrack, listener = std::move(mPullListener)]() { 548 if (track->IsDestroyed()) { 549 return; 550 } 551 track->RemoveListener(listener); 552 track->SetPullingEnabled(false); 553 })); 554 return NS_OK; 555 } 556 557 nsresult MediaEngineFakeAudioSource::Reconfigure( 558 const MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, 559 const char** aOutBadConstraint) { 560 return NS_OK; 561 } 562 563 void AudioSourcePullListener::NotifyPull(MediaTrackGraph* aGraph, 564 TrackTime aEndOfAppendedData, 565 TrackTime aDesiredTime) { 566 TRACE_COMMENT("SourceMediaTrack::NotifyPull", "SourceMediaTrack %p", 567 mTrack.get()); 568 AudioSegment segment; 569 TrackTicks delta = aDesiredTime - aEndOfAppendedData; 570 CheckedInt<size_t> bufferSize(sizeof(int16_t)); 571 bufferSize *= delta; 572 RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize); 573 int16_t* dest = static_cast<int16_t*>(buffer->Data()); 574 mSineGenerator->generate(dest, delta); 575 AutoTArray<const int16_t*, 1> channels; 576 channels.AppendElement(dest); 577 segment.AppendFrames(buffer.forget(), channels, delta, mPrincipalHandle); 578 mTrack->AppendData(&segment); 579 } 580 581 MediaEngineFake::MediaEngineFake() = default; 582 MediaEngineFake::~MediaEngineFake() = default; 583 584 void MediaEngineFake::EnumerateDevices( 585 MediaSourceEnum aMediaSource, MediaSinkEnum aMediaSink, 586 nsTArray<RefPtr<MediaDevice>>* aDevices) { 587 AssertIsOnOwningThread(); 588 using IsScary = MediaDevice::IsScary; 589 using OsPromptable = MediaDevice::OsPromptable; 590 591 if (aMediaSink == MediaSinkEnum::Speaker) { 592 NS_WARNING("No default implementation for MediaSinkEnum::Speaker"); 593 } 594 595 switch (aMediaSource) { 596 case MediaSourceEnum::Camera: { 597 nsString name = FakeVideoName(); 598 aDevices->EmplaceBack( 599 new MediaDevice(this, aMediaSource, name, /*aRawId=*/name, 600 MediaEngineFakeVideoSource::GetGroupId(), IsScary::No, 601 OsPromptable::No)); 602 return; 603 } 604 case MediaSourceEnum::Microphone: 605 aDevices->EmplaceBack( 606 new MediaDevice(this, aMediaSource, u"Default Audio Device"_ns, 607 MediaEngineFakeAudioSource::GetUUID(), 608 MediaEngineFakeAudioSource::GetGroupId(), IsScary::No, 609 OsPromptable::No)); 610 return; 611 default: 612 MOZ_ASSERT_UNREACHABLE("Unsupported source type"); 613 return; 614 } 615 } 616 617 RefPtr<MediaEngineSource> MediaEngineFake::CreateSource( 618 const MediaDevice* aMediaDevice) { 619 MOZ_ASSERT(aMediaDevice->mEngine == this); 620 switch (aMediaDevice->mMediaSource) { 621 case MediaSourceEnum::Camera: 622 return new MediaEngineFakeVideoSource(); 623 case MediaSourceEnum::Microphone: 624 return new MediaEngineFakeAudioSource(); 625 default: 626 MOZ_ASSERT_UNREACHABLE("Unsupported source type"); 627 return nullptr; 628 } 629 } 630 631 RefPtr<MediaEngineSource> MediaEngineFake::CreateSourceFrom( 632 const MediaEngineSource* aSource, const MediaDevice* aMediaDevice) { 633 MOZ_ASSERT(aMediaDevice->mEngine == this); 634 switch (aMediaDevice->mMediaSource) { 635 case MediaSourceEnum::Camera: 636 return MediaEngineFakeVideoSource::CreateFrom( 637 static_cast<const MediaEngineFakeVideoSource*>(aSource)); 638 case MediaSourceEnum::Microphone: 639 // No main thread members that need to be deep cloned. 640 return new MediaEngineFakeAudioSource(); 641 default: 642 MOZ_ASSERT_UNREACHABLE("Unsupported source type"); 643 return nullptr; 644 } 645 } 646 647 } // namespace mozilla