dom/fmradio/FMRadio.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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
    36 {
    37 public:
    38   NS_DECL_ISUPPORTS_INHERITED
    40   FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio)
    41     : DOMRequest(aWindow)
    42     , mType(FMRadioRequestArgs::T__None)
    43   {
    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));
    48   }
    50   FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio,
    51     FMRadioRequestArgs::Type aType)
    52     : DOMRequest(aWindow)
    53   {
    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;
    60   }
    62   ~FMRadioRequest() { }
    64   NS_IMETHODIMP
    65   Run()
    66   {
    67     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
    69     nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mFMRadio);
    70     if (!target) {
    71       return NS_OK;
    72     }
    74     FMRadio* fmRadio = static_cast<FMRadio*>(
    75       static_cast<nsIDOMEventTarget*>(target));
    77     if (fmRadio->mIsShutdown) {
    78       return NS_OK;
    79     }
    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();
    88         }
    90         FireSuccess(JS::UndefinedHandleValue);
    91         break;
    92       default:
    93         MOZ_CRASH();
    94     }
    96     return NS_OK;
    97   }
    99 private:
   100   FMRadioRequestArgs::Type mType;
   101   nsWeakPtr mFMRadio;
   102 };
   104 NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest)
   106 FMRadio::FMRadio()
   107   : mHeadphoneState(SWITCH_STATE_OFF)
   108   , mAudioChannelAgentEnabled(false)
   109   , mHasInternalAntenna(false)
   110   , mIsShutdown(false)
   111 {
   112   LOG("FMRadio is initialized.");
   114   SetIsDOMBinding();
   115 }
   117 FMRadio::~FMRadio()
   118 {
   119 }
   121 void
   122 FMRadio::Init(nsPIDOMWindow *aWindow)
   123 {
   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);
   135   }
   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;
   167 }
   169 void
   170 FMRadio::Shutdown()
   171 {
   172   IFMRadioService::Singleton()->RemoveObserver(this);
   174   if (!mHasInternalAntenna) {
   175     UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
   176   }
   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;
   184 }
   186 JSObject*
   187 FMRadio::WrapObject(JSContext* aCx)
   188 {
   189   return FMRadioBinding::Wrap(aCx, this);
   190 }
   192 void
   193 FMRadio::Notify(const SwitchEvent& aEvent)
   194 {
   195   MOZ_ASSERT(!mHasInternalAntenna);
   197   if (mHeadphoneState != aEvent.status()) {
   198     mHeadphoneState = aEvent.status();
   200     DispatchTrustedEvent(NS_LITERAL_STRING("antennaavailablechange"));
   201   }
   202 }
   204 void
   205 FMRadio::Notify(const FMRadioEventType& aType)
   206 {
   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;
   218         }
   220         DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
   221       }
   222       break;
   223     default:
   224       MOZ_CRASH();
   225   }
   226 }
   228 /* static */
   229 bool
   230 FMRadio::Enabled()
   231 {
   232   return IFMRadioService::Singleton()->IsEnabled();
   233 }
   235 bool
   236 FMRadio::AntennaAvailable() const
   237 {
   238   return mHasInternalAntenna ? true : (mHeadphoneState != SWITCH_STATE_OFF) &&
   239     (mHeadphoneState != SWITCH_STATE_UNKNOWN);
   240 }
   242 Nullable<double>
   243 FMRadio::GetFrequency() const
   244 {
   245   return Enabled() ?
   246     Nullable<double>(IFMRadioService::Singleton()->GetFrequency()) :
   247     Nullable<double>();
   248 }
   250 double
   251 FMRadio::FrequencyUpperBound() const
   252 {
   253   return IFMRadioService::Singleton()->GetFrequencyUpperBound();
   254 }
   256 double
   257 FMRadio::FrequencyLowerBound() const
   258 {
   259   return IFMRadioService::Singleton()->GetFrequencyLowerBound();
   260 }
   262 double
   263 FMRadio::ChannelWidth() const
   264 {
   265   return IFMRadioService::Singleton()->GetChannelWidth();
   266 }
   268 already_AddRefed<DOMRequest>
   269 FMRadio::Enable(double aFrequency)
   270 {
   271   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   272   if (!win) {
   273     return nullptr;
   274   }
   276   nsRefPtr<FMRadioRequest> r =
   277     new FMRadioRequest(win, this, FMRadioRequestArgs::TEnableRequestArgs);
   278   IFMRadioService::Singleton()->Enable(aFrequency, r);
   280   return r.forget();
   281 }
   283 already_AddRefed<DOMRequest>
   284 FMRadio::Disable()
   285 {
   286   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   287   if (!win) {
   288     return nullptr;
   289   }
   291   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   292   IFMRadioService::Singleton()->Disable(r);
   294   return r.forget();
   295 }
   297 already_AddRefed<DOMRequest>
   298 FMRadio::SetFrequency(double aFrequency)
   299 {
   300   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   301   if (!win) {
   302     return nullptr;
   303   }
   305   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   306   IFMRadioService::Singleton()->SetFrequency(aFrequency, r);
   308   return r.forget();
   309 }
   311 already_AddRefed<DOMRequest>
   312 FMRadio::SeekUp()
   313 {
   314   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   315   if (!win) {
   316     return nullptr;
   317   }
   319   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   320   IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_UP, r);
   322   return r.forget();
   323 }
   325 already_AddRefed<DOMRequest>
   326 FMRadio::SeekDown()
   327 {
   328   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   329   if (!win) {
   330     return nullptr;
   331   }
   333   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   334   IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_DOWN, r);
   336   return r.forget();
   337 }
   339 already_AddRefed<DOMRequest>
   340 FMRadio::CancelSeek()
   341 {
   342   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   343   if (!win) {
   344     return nullptr;
   345   }
   347   nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
   348   IFMRadioService::Singleton()->CancelSeek(r);
   350   return r.forget();
   351 }
   353 NS_IMETHODIMP
   354 FMRadio::HandleEvent(nsIDOMEvent* aEvent)
   355 {
   356   nsAutoString type;
   357   aEvent->GetType(type);
   359   if (!type.EqualsLiteral("visibilitychange")) {
   360     return NS_ERROR_FAILURE;
   361   }
   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;
   371 }
   373 void
   374 FMRadio::EnableAudioChannelAgent()
   375 {
   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;
   383 }
   385 NS_IMETHODIMP
   386 FMRadio::CanPlayChanged(int32_t aCanPlay)
   387 {
   388   SetCanPlay(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
   389   return NS_OK;
   390 }
   392 NS_IMETHODIMP
   393 FMRadio::WindowVolumeChanged()
   394 {
   395   return NS_ERROR_NOT_IMPLEMENTED;
   396 }
   398 void
   399 FMRadio::SetCanPlay(bool aCanPlay)
   400 {
   401   IFMRadioService::Singleton()->EnableAudio(aCanPlay);
   402 }
   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

mercurial