Bumping manifests a=b2g-bump
[gecko.git] / dom / fmradio / FMRadio.cpp
blobada434208ba931457974e574388f7d7ad540a31b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/FMRadio.h"
8 #include "nsContentUtils.h"
9 #include "mozilla/Hal.h"
10 #include "mozilla/HalTypes.h"
11 #include "mozilla/Preferences.h"
12 #include "mozilla/dom/FMRadioBinding.h"
13 #include "mozilla/dom/ContentChild.h"
14 #include "mozilla/dom/PFMRadioChild.h"
15 #include "mozilla/dom/FMRadioService.h"
16 #include "DOMRequest.h"
17 #include "nsDOMClassInfo.h"
18 #include "nsIDocShell.h"
19 #include "nsIInterfaceRequestorUtils.h"
20 #include "nsIAudioManager.h"
22 #undef LOG
23 #define LOG(args...) FM_LOG("FMRadio", args)
25 // The pref indicates if the device has an internal antenna.
26 // If the pref is true, the antanna will be always available.
27 #define DOM_FM_ANTENNA_INTERNAL_PREF "dom.fmradio.antenna.internal"
29 using namespace mozilla::hal;
30 using mozilla::Preferences;
32 BEGIN_FMRADIO_NAMESPACE
34 class FMRadioRequest MOZ_FINAL : public FMRadioReplyRunnable
35 , public DOMRequest
37 public:
38 NS_DECL_ISUPPORTS_INHERITED
40 FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio)
41 : DOMRequest(aWindow)
42 , mType(FMRadioRequestArgs::T__None)
44 // |FMRadio| inherits from |nsIDOMEventTarget| and |nsISupportsWeakReference|
45 // which both inherits from nsISupports, so |nsISupports| is an ambiguous
46 // base of |FMRadio|, we have to cast |aFMRadio| to one of the base classes.
47 mFMRadio = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aFMRadio));
50 FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio,
51 FMRadioRequestArgs::Type aType)
52 : DOMRequest(aWindow)
54 MOZ_ASSERT(aType >= FMRadioRequestArgs::T__None &&
55 aType <= FMRadioRequestArgs::T__Last,
56 "Wrong FMRadioRequestArgs in FMRadioRequest");
58 mFMRadio = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aFMRadio));
59 mType = aType;
62 ~FMRadioRequest() { }
64 NS_IMETHODIMP
65 Run()
67 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
69 nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mFMRadio);
70 if (!target) {
71 return NS_OK;
74 FMRadio* fmRadio = static_cast<FMRadio*>(
75 static_cast<nsIDOMEventTarget*>(target));
77 if (fmRadio->mIsShutdown) {
78 return NS_OK;
81 switch (mResponseType.type()) {
82 case FMRadioResponseType::TErrorResponse:
83 FireError(mResponseType.get_ErrorResponse().error());
84 break;
85 case FMRadioResponseType::TSuccessResponse:
86 if (mType == FMRadioRequestArgs::TEnableRequestArgs) {
87 fmRadio->EnableAudioChannelAgent();
90 FireSuccess(JS::UndefinedHandleValue);
91 break;
92 default:
93 MOZ_CRASH();
96 return NS_OK;
99 private:
100 FMRadioRequestArgs::Type mType;
101 nsWeakPtr mFMRadio;
104 NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest)
106 FMRadio::FMRadio()
107 : mHeadphoneState(SWITCH_STATE_OFF)
108 , mAudioChannelAgentEnabled(false)
109 , mHasInternalAntenna(false)
110 , mIsShutdown(false)
112 LOG("FMRadio is initialized.");
114 SetIsDOMBinding();
117 FMRadio::~FMRadio()
121 void
122 FMRadio::Init(nsPIDOMWindow *aWindow)
124 BindToOwner(aWindow);
126 IFMRadioService::Singleton()->AddObserver(this);
128 mHasInternalAntenna = Preferences::GetBool(DOM_FM_ANTENNA_INTERNAL_PREF,
129 /* default = */ false);
130 if (mHasInternalAntenna) {
131 LOG("We have an internal antenna.");
132 } else {
133 mHeadphoneState = GetCurrentSwitchState(SWITCH_HEADPHONES);
134 RegisterSwitchObserver(SWITCH_HEADPHONES, this);
137 nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
138 NS_ENSURE_TRUE_VOID(target);
139 target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
140 /* useCapture = */ true,
141 /* wantsUntrusted = */ false);
144 // All of the codes below are for AudioChannel. We can directly return here
145 // if preferences doesn't enable AudioChannelService.
146 NS_ENSURE_TRUE_VOID(Preferences::GetBool("media.useAudioChannelService"));
148 nsCOMPtr<nsIAudioChannelAgent> audioChannelAgent =
149 do_CreateInstance("@mozilla.org/audiochannelagent;1");
150 NS_ENSURE_TRUE_VOID(audioChannelAgent);
152 audioChannelAgent->InitWithWeakCallback(
153 GetOwner(),
154 nsIAudioChannelAgent::AUDIO_AGENT_CHANNEL_CONTENT,
155 this);
157 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
158 NS_ENSURE_TRUE_VOID(docshell);
160 bool isActive = false;
161 docshell->GetIsActive(&isActive);
162 audioChannelAgent->SetVisibilityState(isActive);
164 // Once all necessary resources are got successfully, we just enabled
165 // mAudioChannelAgent.
166 mAudioChannelAgent = audioChannelAgent;
169 void
170 FMRadio::Shutdown()
172 IFMRadioService::Singleton()->RemoveObserver(this);
174 if (!mHasInternalAntenna) {
175 UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
178 nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
179 NS_ENSURE_TRUE_VOID(target);
180 target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
181 /* useCapture = */ true);
183 mIsShutdown = true;
186 JSObject*
187 FMRadio::WrapObject(JSContext* aCx)
189 return FMRadioBinding::Wrap(aCx, this);
192 void
193 FMRadio::Notify(const SwitchEvent& aEvent)
195 MOZ_ASSERT(!mHasInternalAntenna);
197 if (mHeadphoneState != aEvent.status()) {
198 mHeadphoneState = aEvent.status();
200 DispatchTrustedEvent(NS_LITERAL_STRING("antennaavailablechange"));
204 void
205 FMRadio::Notify(const FMRadioEventType& aType)
207 switch (aType) {
208 case FrequencyChanged:
209 DispatchTrustedEvent(NS_LITERAL_STRING("frequencychange"));
210 break;
211 case EnabledChanged:
212 if (Enabled()) {
213 DispatchTrustedEvent(NS_LITERAL_STRING("enabled"));
214 } else {
215 if (mAudioChannelAgentEnabled) {
216 mAudioChannelAgent->StopPlaying();
217 mAudioChannelAgentEnabled = false;
220 DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
222 break;
223 default:
224 MOZ_CRASH();
228 /* static */
229 bool
230 FMRadio::Enabled()
232 return IFMRadioService::Singleton()->IsEnabled();
235 bool
236 FMRadio::AntennaAvailable() const
238 return mHasInternalAntenna ? true : (mHeadphoneState != SWITCH_STATE_OFF) &&
239 (mHeadphoneState != SWITCH_STATE_UNKNOWN);
242 Nullable<double>
243 FMRadio::GetFrequency() const
245 return Enabled() ?
246 Nullable<double>(IFMRadioService::Singleton()->GetFrequency()) :
247 Nullable<double>();
250 double
251 FMRadio::FrequencyUpperBound() const
253 return IFMRadioService::Singleton()->GetFrequencyUpperBound();
256 double
257 FMRadio::FrequencyLowerBound() const
259 return IFMRadioService::Singleton()->GetFrequencyLowerBound();
262 double
263 FMRadio::ChannelWidth() const
265 return IFMRadioService::Singleton()->GetChannelWidth();
268 already_AddRefed<DOMRequest>
269 FMRadio::Enable(double aFrequency)
271 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
272 if (!win) {
273 return nullptr;
276 nsRefPtr<FMRadioRequest> r =
277 new FMRadioRequest(win, this, FMRadioRequestArgs::TEnableRequestArgs);
278 IFMRadioService::Singleton()->Enable(aFrequency, r);
280 return r.forget();
283 already_AddRefed<DOMRequest>
284 FMRadio::Disable()
286 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
287 if (!win) {
288 return nullptr;
291 nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
292 IFMRadioService::Singleton()->Disable(r);
294 return r.forget();
297 already_AddRefed<DOMRequest>
298 FMRadio::SetFrequency(double aFrequency)
300 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
301 if (!win) {
302 return nullptr;
305 nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
306 IFMRadioService::Singleton()->SetFrequency(aFrequency, r);
308 return r.forget();
311 already_AddRefed<DOMRequest>
312 FMRadio::SeekUp()
314 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
315 if (!win) {
316 return nullptr;
319 nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
320 IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_UP, r);
322 return r.forget();
325 already_AddRefed<DOMRequest>
326 FMRadio::SeekDown()
328 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
329 if (!win) {
330 return nullptr;
333 nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
334 IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_DOWN, r);
336 return r.forget();
339 already_AddRefed<DOMRequest>
340 FMRadio::CancelSeek()
342 nsCOMPtr<nsPIDOMWindow> win = GetOwner();
343 if (!win) {
344 return nullptr;
347 nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
348 IFMRadioService::Singleton()->CancelSeek(r);
350 return r.forget();
353 NS_IMETHODIMP
354 FMRadio::HandleEvent(nsIDOMEvent* aEvent)
356 nsAutoString type;
357 aEvent->GetType(type);
359 if (!type.EqualsLiteral("visibilitychange")) {
360 return NS_ERROR_FAILURE;
363 nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
364 NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
366 bool isActive = false;
367 docshell->GetIsActive(&isActive);
369 mAudioChannelAgent->SetVisibilityState(isActive);
370 return NS_OK;
373 void
374 FMRadio::EnableAudioChannelAgent()
376 NS_ENSURE_TRUE_VOID(mAudioChannelAgent);
378 int32_t playingState = 0;
379 mAudioChannelAgent->StartPlaying(&playingState);
380 SetCanPlay(playingState == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
382 mAudioChannelAgentEnabled = true;
385 NS_IMETHODIMP
386 FMRadio::CanPlayChanged(int32_t aCanPlay)
388 SetCanPlay(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
389 return NS_OK;
392 NS_IMETHODIMP
393 FMRadio::WindowVolumeChanged()
395 return NS_ERROR_NOT_IMPLEMENTED;
398 void
399 FMRadio::SetCanPlay(bool aCanPlay)
401 IFMRadioService::Singleton()->EnableAudio(aCanPlay);
404 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
405 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
406 NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
407 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
408 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
410 NS_IMPL_ADDREF_INHERITED(FMRadio, DOMEventTargetHelper)
411 NS_IMPL_RELEASE_INHERITED(FMRadio, DOMEventTargetHelper)
413 END_FMRADIO_NAMESPACE