summaryrefslogtreecommitdiffstats
path: root/dom/media/MediaDevices.h
blob: fa6a11c8fba9c4f75dbfd9b21a3255802b35e7ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_MediaDevices_h
#define mozilla_dom_MediaDevices_h

#include "MediaEventSource.h"
#include "js/RootingAPI.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/UseCounter.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCOMPtr.h"
#include "nsID.h"
#include "nsISupports.h"
#include "nsTHashSet.h"

class AudioDeviceInfo;

namespace mozilla {

class LocalMediaDevice;
class MediaDevice;
class MediaMgrError;
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
class MozPromise;

namespace media {
template <typename T>
class Refcountable;
}  // namespace media

namespace dom {

class Promise;
struct MediaStreamConstraints;
struct DisplayMediaStreamConstraints;
struct MediaTrackSupportedConstraints;
struct AudioOutputOptions;

class MediaDevices final : public DOMEventTargetHelper {
 public:
  using SinkInfoPromise = MozPromise<RefPtr<AudioDeviceInfo>, nsresult, true>;

  explicit MediaDevices(nsPIDOMWindowInner* aWindow);

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaDevices, DOMEventTargetHelper)

  JSObject* WrapObject(JSContext* cx,
                       JS::Handle<JSObject*> aGivenProto) override;

  // No code needed, as MediaTrackSupportedConstraints members default to true.
  void GetSupportedConstraints(MediaTrackSupportedConstraints& aResult){};

  already_AddRefed<Promise> GetUserMedia(
      const MediaStreamConstraints& aConstraints, CallerType aCallerType,
      ErrorResult& aRv);

  already_AddRefed<Promise> EnumerateDevices(ErrorResult& aRv);

  already_AddRefed<Promise> GetDisplayMedia(
      const DisplayMediaStreamConstraints& aConstraints, CallerType aCallerType,
      ErrorResult& aRv);

  already_AddRefed<Promise> SelectAudioOutput(
      const AudioOutputOptions& aOptions, CallerType aCallerType,
      ErrorResult& aRv);

  // Get the sink that corresponds to the given device id.
  // The returned promise will be resolved with the device
  // information if the aDeviceId matches a device that would be exposed by
  // enumerateDevices().
  // The promise will be rejected with NS_ERROR_NOT_AVAILABLE if aDeviceId
  // does not match any exposed device.
  RefPtr<SinkInfoPromise> GetSinkDevice(const nsString& aDeviceId);

  // Called when MediaManager encountered a change in its device lists.
  void OnDeviceChange();

  void SetupDeviceChangeListener();

  mozilla::dom::EventHandlerNonNull* GetOndevicechange();
  void SetOndevicechange(mozilla::dom::EventHandlerNonNull* aCallback);

  void EventListenerAdded(nsAtom* aType) override;
  using DOMEventTargetHelper::EventListenerAdded;

  void BackgroundStateChanged() { MaybeResumeDeviceExposure(); }
  void WindowResumed() { MaybeResumeDeviceExposure(); }
  void BrowserWindowBecameActive() { MaybeResumeDeviceExposure(); }

 private:
  using MediaDeviceSet = nsTArray<RefPtr<MediaDevice>>;
  using MediaDeviceSetRefCnt = media::Refcountable<MediaDeviceSet>;
  using LocalMediaDeviceSet = nsTArray<RefPtr<LocalMediaDevice>>;

  virtual ~MediaDevices();
  void MaybeResumeDeviceExposure();
  void ResumeEnumerateDevices(
      nsTArray<RefPtr<Promise>>&& aPromises,
      RefPtr<const MediaDeviceSetRefCnt> aExposedDevices) const;
  RefPtr<MediaDeviceSetRefCnt> FilterExposedDevices(
      const MediaDeviceSet& aDevices) const;
  bool ShouldQueueDeviceChange(const MediaDeviceSet& aExposedDevices) const;
  void ResolveEnumerateDevicesPromise(
      Promise* aPromise, const LocalMediaDeviceSet& aDevices) const;

  nsTHashSet<nsString> mExplicitlyGrantedAudioOutputRawIds;
  nsTArray<RefPtr<Promise>> mPendingEnumerateDevicesPromises;
  // Set only once, if and when required.
  mutable nsString mDefaultOutputLabel;

  // Connect/Disconnect on main thread only
  MediaEventListener mDeviceChangeListener;
  // Ordered set of the system physical devices when devicechange event
  // decisions were last performed.
  RefPtr<const MediaDeviceSetRefCnt> mLastPhysicalDevices;
  bool mIsDeviceChangeListenerSetUp = false;
  bool mHaveUnprocessedDeviceListChange = false;
  bool mCanExposeMicrophoneInfo = false;
  bool mCanExposeCameraInfo = false;

  void RecordAccessTelemetry(const UseCounter counter) const;
};

}  // namespace dom
}  // namespace mozilla

#endif  // mozilla_dom_MediaDevices_h