mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 870676: Part 1 - Implement mozFMRadio in WebIDL, r=khuey,baku
This commit is contained in:
parent
a1cfae0032
commit
8397e0b9ea
@ -6,9 +6,6 @@
|
||||
|
||||
Cu.import('resource://gre/modules/ContactService.jsm');
|
||||
Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
|
||||
#ifdef MOZ_B2G_FM
|
||||
Cu.import('resource://gre/modules/DOMFMRadioParent.jsm');
|
||||
#endif
|
||||
Cu.import('resource://gre/modules/AlarmService.jsm');
|
||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
|
||||
|
@ -172,9 +172,6 @@
|
||||
@BINPATH@/components/dom_cellbroadcast.xpt
|
||||
@BINPATH@/components/dom_wappush.xpt
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
@BINPATH@/components/dom_fm.xpt
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@ -475,10 +472,6 @@
|
||||
@BINPATH@/components/NetworkInterfaceListService.manifest
|
||||
@BINPATH@/components/NetworkInterfaceListService.js
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
@BINPATH@/components/DOMFMRadioChild.js
|
||||
@BINPATH@/components/DOMFMRadio.manifest
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_DBUS
|
||||
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
||||
#endif
|
||||
|
@ -638,6 +638,7 @@ GK_ATOM(onalerting, "onalerting")
|
||||
GK_ATOM(onanimationend, "onanimationend")
|
||||
GK_ATOM(onanimationiteration, "onanimationiteration")
|
||||
GK_ATOM(onanimationstart, "onanimationstart")
|
||||
GK_ATOM(onantennaavailablechange, "onantennaavailablechange")
|
||||
GK_ATOM(onAppCommand, "onAppCommand")
|
||||
GK_ATOM(onaudioprocess, "onaudioprocess")
|
||||
GK_ATOM(onbeforecopy, "onbeforecopy")
|
||||
@ -709,6 +710,7 @@ GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
|
||||
GK_ATOM(onerror, "onerror")
|
||||
GK_ATOM(onfailed, "onfailed")
|
||||
GK_ATOM(onfocus, "onfocus")
|
||||
GK_ATOM(onfrequencychange, "onfrequencychange")
|
||||
GK_ATOM(onget, "onget")
|
||||
GK_ATOM(ongroupchange, "ongroupchange")
|
||||
GK_ATOM(onhashchange, "onhashchange")
|
||||
@ -785,8 +787,6 @@ GK_ATOM(onshow, "onshow")
|
||||
GK_ATOM(onstatechange, "onstatechange")
|
||||
GK_ATOM(onstatuschanged, "onstatuschanged")
|
||||
GK_ATOM(onstkcommand, "onstkcommand")
|
||||
GK_ATOM(onantennastatechange, "onantennastatechange")
|
||||
GK_ATOM(onseekcomplete, "onseekcomplete")
|
||||
GK_ATOM(onstksessionend, "onstksessionend")
|
||||
GK_ATOM(onsubmit, "onsubmit")
|
||||
GK_ATOM(onsuccess, "onsuccess")
|
||||
|
@ -65,6 +65,10 @@
|
||||
#include "AudioChannelManager.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
#include "mozilla/dom/FMRadio.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
@ -195,6 +199,13 @@ Navigator::Invalidate()
|
||||
mBatteryManager = nullptr;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
if (mFMRadio) {
|
||||
mFMRadio->Shutdown();
|
||||
mFMRadio = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mPowerManager) {
|
||||
mPowerManager->Shutdown();
|
||||
mPowerManager = nullptr;
|
||||
@ -1044,6 +1055,34 @@ Navigator::GetMozNotification(ErrorResult& aRv)
|
||||
return mNotification;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
|
||||
using mozilla::dom::FMRadio;
|
||||
|
||||
FMRadio*
|
||||
Navigator::GetMozFMRadio(ErrorResult& aRv)
|
||||
{
|
||||
if (!mFMRadio) {
|
||||
if (!mWindow) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
|
||||
|
||||
mFMRadio = new FMRadio();
|
||||
mFMRadio->Init(mWindow);
|
||||
}
|
||||
|
||||
return mFMRadio;
|
||||
}
|
||||
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator::nsINavigatorBattery
|
||||
//*****************************************************************************
|
||||
|
||||
battery::BatteryManager*
|
||||
Navigator::GetBattery(ErrorResult& aRv)
|
||||
{
|
||||
@ -1710,6 +1749,16 @@ Navigator::HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
}
|
||||
#endif // MOZ_B2G_BT
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return win && CheckPermission(win, "fmradio");
|
||||
}
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
/* static */
|
||||
bool
|
||||
|
@ -51,6 +51,10 @@ namespace battery {
|
||||
class BatteryManager;
|
||||
} // namespace battery
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
class FMRadio;
|
||||
#endif
|
||||
|
||||
class DesktopNotificationCenter;
|
||||
class MobileMessageManager;
|
||||
class MozIdleObserver;
|
||||
@ -230,6 +234,9 @@ public:
|
||||
#ifdef MOZ_GAMEPAD
|
||||
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
|
||||
#endif // MOZ_GAMEPAD
|
||||
#ifdef MOZ_B2G_FM
|
||||
FMRadio* GetMozFMRadio(ErrorResult& aRv);
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT
|
||||
bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
|
||||
#endif // MOZ_B2G_BT
|
||||
@ -283,6 +290,9 @@ public:
|
||||
#ifdef MOZ_B2G_BT
|
||||
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_BT
|
||||
#ifdef MOZ_B2G_FM
|
||||
static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_FM
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
@ -314,6 +324,9 @@ private:
|
||||
nsRefPtr<Geolocation> mGeolocation;
|
||||
nsRefPtr<DesktopNotificationCenter> mNotification;
|
||||
nsRefPtr<battery::BatteryManager> mBatteryManager;
|
||||
#ifdef MOZ_B2G_FM
|
||||
nsRefPtr<FMRadio> mFMRadio;
|
||||
#endif
|
||||
nsRefPtr<power::PowerManager> mPowerManager;
|
||||
nsRefPtr<MobileMessageManager> mMobileMessageManager;
|
||||
#ifdef MOZ_B2G_RIL
|
||||
|
@ -537,11 +537,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_DEFINE_CLASSINFO_DATA(FMRadio, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
@ -1399,13 +1394,6 @@ nsDOMClassInfo::Init()
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
DOM_CLASSINFO_MAP_BEGIN(FMRadio, nsIFMRadio)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIFMRadio)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
||||
|
@ -130,10 +130,6 @@ DOMCI_CLASS(MediaQueryList)
|
||||
DOMCI_CLASS(MozIccManager)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
DOMCI_CLASS(FMRadio)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOMCI_CLASS(BluetoothDevice)
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ endif
|
||||
|
||||
ifdef MOZ_B2G_FM
|
||||
DOM_SRCDIRS += \
|
||||
dom/fm \
|
||||
dom/fmradio \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
# DOMFMRadio.js
|
||||
component {901f8a83-03a6-4be9-bb8f-35387d3849da} DOMFMRadioChild.js
|
||||
contract @mozilla.org/domfmradio;1 {901f8a83-03a6-4be9-bb8f-35387d3849da}
|
||||
category JavaScript-navigator-property mozFMRadio @mozilla.org/domfmradio;1
|
@ -1,423 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict"
|
||||
let DEBUG = 0;
|
||||
if (DEBUG)
|
||||
debug = function (s) { dump("-*- DOMFMRadioChild: " + s + "\n"); };
|
||||
else
|
||||
debug = function (s) { };
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
const DOMFMMANAGER_CONTRACTID = "@mozilla.org/domfmradio;1";
|
||||
const DOMFMMANAGER_CID = Components.ID("{901f8a83-03a6-4be9-bb8f-35387d3849da}");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
|
||||
return Cc["@mozilla.org/dom/dom-request-service;1"]
|
||||
.getService(Ci.nsIDOMRequestService);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
function DOMFMRadioChild() { }
|
||||
|
||||
DOMFMRadioChild.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
classID: DOMFMMANAGER_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: DOMFMMANAGER_CID,
|
||||
contractID: DOMFMMANAGER_CONTRACTID,
|
||||
classDescription: "DOMFMRadio",
|
||||
interfaces: [Ci.nsIDOMFMRadio],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT
|
||||
}),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMFMRadio,
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation
|
||||
init: function(aWindow) {
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "fmradio");
|
||||
this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
if (!this._hasPrivileges) {
|
||||
Cu.reportError("NO FMRADIO PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
const messages = ["DOMFMRadio:enable:Return:OK",
|
||||
"DOMFMRadio:enable:Return:NO",
|
||||
"DOMFMRadio:disable:Return:OK",
|
||||
"DOMFMRadio:disable:Return:NO",
|
||||
"DOMFMRadio:setFrequency:Return:OK",
|
||||
"DOMFMRadio:setFrequency:Return:NO",
|
||||
"DOMFMRadio:seekUp:Return:OK",
|
||||
"DOMFMRadio:seekUp:Return:NO",
|
||||
"DOMFMRadio:seekDown:Return:OK",
|
||||
"DOMFMRadio:seekDown:Return:NO",
|
||||
"DOMFMRadio:cancelSeek:Return:OK",
|
||||
"DOMFMRadio:cancelSeek:Return:NO",
|
||||
"DOMFMRadio:frequencyChange",
|
||||
"DOMFMRadio:powerStateChange",
|
||||
"DOMFMRadio:antennaChange"];
|
||||
this.initDOMRequestHelper(aWindow, messages);
|
||||
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Ci.nsIEventListenerService);
|
||||
|
||||
els.addSystemEventListener(aWindow, "visibilitychange",
|
||||
this._updateVisibility.bind(this),
|
||||
/* useCapture = */ true);
|
||||
|
||||
this._visibility = aWindow.document.visibilityState;
|
||||
// Unlike the |enabled| getter, this is true if *this* DOM window
|
||||
// has successfully enabled the FM radio more recently than
|
||||
// disabling it.
|
||||
this._haveEnabledRadio = false;
|
||||
},
|
||||
|
||||
// Called from DOMRequestIpcHelper
|
||||
uninit: function() {
|
||||
this._onFrequencyChange = null;
|
||||
this._onAntennaChange = null;
|
||||
this._onDisabled = null;
|
||||
this._onEnabled = null;
|
||||
},
|
||||
|
||||
_createEvent: function(name) {
|
||||
return new this._window.Event(name);
|
||||
},
|
||||
|
||||
_sendMessageForRequest: function(name, data, request) {
|
||||
let id = this.getRequestId(request);
|
||||
cpmm.sendAsyncMessage(name, {
|
||||
data: data,
|
||||
rid: id,
|
||||
mid: this._id
|
||||
});
|
||||
},
|
||||
|
||||
_fireFrequencyChangeEvent: function() {
|
||||
let e = this._createEvent("frequencychange");
|
||||
if (this._onFrequencyChange) {
|
||||
this._onFrequencyChange.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
_firePowerStateChangeEvent: function() {
|
||||
let _enabled = this.enabled;
|
||||
debug("Current power state: " + _enabled);
|
||||
if (_enabled) {
|
||||
let e = this._createEvent("enabled");
|
||||
if (this._onEnabled) {
|
||||
this._onEnabled.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
} else {
|
||||
let e = this._createEvent("disabled");
|
||||
if (this._onDisabled) {
|
||||
this._onDisabled.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
}
|
||||
},
|
||||
|
||||
_fireAntennaAvailableChangeEvent: function() {
|
||||
let e = this._createEvent("antennaavailablechange");
|
||||
if (this._onAntennaChange) {
|
||||
this._onAntennaChange.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
_updateVisibility: function(evt) {
|
||||
this._visibility = evt.target.visibilityState;
|
||||
// Only notify visibility state when we "own" the radio stream.
|
||||
if (this._haveEnabledRadio) {
|
||||
this._notifyVisibility();
|
||||
}
|
||||
},
|
||||
|
||||
_notifyVisibility: function() {
|
||||
cpmm.sendAsyncMessage("DOMFMRadio:updateVisibility", this._visibility);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
if (msg.mid && msg.mid != this._id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let request;
|
||||
switch (aMessage.name) {
|
||||
case "DOMFMRadio:enable:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:enable:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "Failed to turn on the FM radio");
|
||||
break;
|
||||
case "DOMFMRadio:disable:Return:OK":
|
||||
this._haveEnabledRadio = false;
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:disable:Return:NO":
|
||||
// If disabling the radio failed, but the hardware is still
|
||||
// on, this DOM window is still responsible for the continued
|
||||
// playback.
|
||||
this._haveEnabledRadio = this.enabled;
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request,
|
||||
"Failed to turn off the FM radio");
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request,
|
||||
"Failed to set the FM radio frequency");
|
||||
break;
|
||||
case "DOMFMRadio:seekUp:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:seekUp:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "FM radio seek-up failed");
|
||||
break;
|
||||
case "DOMFMRadio:seekDown:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:seekDown:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "FM radio seek-down failed");
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "Failed to cancel seek");
|
||||
break;
|
||||
case "DOMFMRadio:powerStateChange":
|
||||
this._firePowerStateChangeEvent();
|
||||
break;
|
||||
case "DOMFMRadio:frequencyChange":
|
||||
this._fireFrequencyChangeEvent();
|
||||
break;
|
||||
case "DOMFMRadio:antennaChange":
|
||||
this._fireAntennaAvailableChangeEvent();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_call: function(name, arg) {
|
||||
var request = this.createRequest();
|
||||
this._sendMessageForRequest("DOMFMRadio:" + name, arg, request);
|
||||
return request;
|
||||
},
|
||||
|
||||
// nsIDOMFMRadio
|
||||
get enabled() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getPowerState")[0];
|
||||
},
|
||||
|
||||
get antennaAvailable() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getAntennaState")[0];
|
||||
},
|
||||
|
||||
get frequency() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getFrequency")[0];
|
||||
},
|
||||
|
||||
get frequencyUpperBound() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.upper;
|
||||
},
|
||||
|
||||
get frequencyLowerBound() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.lower;
|
||||
},
|
||||
|
||||
get channelWidth() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.channelWidth;
|
||||
},
|
||||
|
||||
set onantennaavailablechange(callback) {
|
||||
this._onAntennaChange = callback;
|
||||
},
|
||||
|
||||
set onenabled(callback) {
|
||||
this._onEnabled = callback;
|
||||
},
|
||||
|
||||
set ondisabled(callback) {
|
||||
this._onDisabled = callback;
|
||||
},
|
||||
|
||||
set onfrequencychange(callback) {
|
||||
this._onFrequencyChange = callback;
|
||||
},
|
||||
|
||||
disable: function nsIDOMFMRadio_disable() {
|
||||
return this._call("disable", null);
|
||||
},
|
||||
|
||||
enable: function nsIDOMFMRadio_enable(frequency) {
|
||||
// FMRadio::Enable() needs the most recent visibility state
|
||||
// synchronously.
|
||||
this._haveEnabledRadio = true;
|
||||
this._notifyVisibility();
|
||||
return this._call("enable", frequency);
|
||||
},
|
||||
|
||||
setFrequency: function nsIDOMFMRadio_setFreq(frequency) {
|
||||
return this._call("setFrequency", frequency);
|
||||
},
|
||||
|
||||
seekDown: function nsIDOMFMRadio_seekDown() {
|
||||
return this._call("seekDown", null);
|
||||
},
|
||||
|
||||
seekUp: function nsIDOMFMRadio_seekUp() {
|
||||
return this._call("seekUp", null);
|
||||
},
|
||||
|
||||
cancelSeek: function nsIDOMFMRadio_cancelSeek() {
|
||||
return this._call("cancelSeek", null);
|
||||
},
|
||||
|
||||
// These are fake implementations, will be replaced by using
|
||||
// nsJSDOMEventTargetHelper, see bug 731746
|
||||
addEventListener: function(type, listener, useCapture) {
|
||||
if (!this._eventListenersByType) {
|
||||
this._eventListenersByType = {};
|
||||
}
|
||||
|
||||
if (!listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (!listeners) {
|
||||
listeners = this._eventListenersByType[type] = [];
|
||||
}
|
||||
|
||||
useCapture = !!useCapture;
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let l = listeners[i];
|
||||
if (l && l.listener === listener && l.useCapture === useCapture) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listeners.push({
|
||||
listener: listener,
|
||||
useCapture: useCapture
|
||||
});
|
||||
},
|
||||
|
||||
removeEventListener: function(type, listener, useCapture) {
|
||||
if (!this._eventListenersByType) {
|
||||
return;
|
||||
}
|
||||
|
||||
useCapture = !!useCapture;
|
||||
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (listeners) {
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let l = listeners[i];
|
||||
if (l && l.listener === listener && l.useCapture === useCapture) {
|
||||
listeners.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dispatchEvent: function(evt) {
|
||||
if (!this._eventListenersByType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type = evt.type;
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (listeners) {
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let listener = listeners[i].listener;
|
||||
|
||||
try {
|
||||
if (typeof listener == "function") {
|
||||
listener.call(this, evt);
|
||||
} else if (listener && listener.handleEvent &&
|
||||
typeof listener.handleEvent == "function") {
|
||||
listener.handleEvent(evt);
|
||||
}
|
||||
} catch (e) {
|
||||
debug("Exception is caught: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMFMRadioChild]);
|
||||
|
@ -1,472 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict"
|
||||
|
||||
let DEBUG = 0;
|
||||
if (DEBUG)
|
||||
debug = function(s) { dump("-*- DOMFMRadioParent component: " + s + "\n"); };
|
||||
else
|
||||
debug = function(s) {};
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC = "mozsettings-changed";
|
||||
const PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC = "profile-before-change";
|
||||
|
||||
const BAND_87500_108000_kHz = 1;
|
||||
const BAND_76000_108000_kHz = 2;
|
||||
const BAND_76000_90000_kHz = 3;
|
||||
|
||||
const FM_BANDS = { };
|
||||
FM_BANDS[BAND_76000_90000_kHz] = {
|
||||
lower: 76000,
|
||||
upper: 90000
|
||||
};
|
||||
|
||||
FM_BANDS[BAND_87500_108000_kHz] = {
|
||||
lower: 87500,
|
||||
upper: 108000
|
||||
};
|
||||
|
||||
FM_BANDS[BAND_76000_108000_kHz] = {
|
||||
lower: 76000,
|
||||
upper: 108000
|
||||
};
|
||||
|
||||
const BAND_SETTING_KEY = "fmRadio.band";
|
||||
const CHANNEL_WIDTH_SETTING_KEY = "fmRadio.channelWidth";
|
||||
|
||||
// Hal types
|
||||
const CHANNEL_WIDTH_200KHZ = 200;
|
||||
const CHANNEL_WIDTH_100KHZ = 100;
|
||||
const CHANNEL_WIDTH_50KHZ = 50;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "FMRadio", function() {
|
||||
return Cc["@mozilla.org/fmradio;1"].getService(Ci.nsIFMRadio);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DOMFMRadioParent"];
|
||||
|
||||
this.DOMFMRadioParent = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISettingsServiceCallback]),
|
||||
|
||||
_initialized: false,
|
||||
|
||||
/* Indicates if the FM radio is currently enabled */
|
||||
_isEnabled: false,
|
||||
|
||||
/* Indicates if the FM radio is currently being enabled */
|
||||
_enabling: false,
|
||||
|
||||
/* Current frequency in KHz */
|
||||
_currentFrequency: 0,
|
||||
|
||||
/* Current band setting */
|
||||
_currentBand: BAND_87500_108000_kHz,
|
||||
|
||||
/* Current channel width */
|
||||
_currentWidth: CHANNEL_WIDTH_100KHZ,
|
||||
|
||||
/* Indicates if the antenna is currently available */
|
||||
_antennaAvailable: true,
|
||||
|
||||
_seeking: false,
|
||||
|
||||
_seekingCallback: null,
|
||||
|
||||
init: function() {
|
||||
if (this._initialized === true) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
this._messages = ["DOMFMRadio:enable", "DOMFMRadio:disable",
|
||||
"DOMFMRadio:setFrequency", "DOMFMRadio:getCurrentBand",
|
||||
"DOMFMRadio:getPowerState", "DOMFMRadio:getFrequency",
|
||||
"DOMFMRadio:getAntennaState",
|
||||
"DOMFMRadio:seekUp", "DOMFMRadio:seekDown",
|
||||
"DOMFMRadio:cancelSeek",
|
||||
"DOMFMRadio:updateVisibility",
|
||||
];
|
||||
this._messages.forEach(function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}.bind(this));
|
||||
|
||||
Services.obs.addObserver(this, PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC, false);
|
||||
Services.obs.addObserver(this, MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC, false);
|
||||
|
||||
this._updatePowerState();
|
||||
|
||||
// Get the band setting and channel width setting
|
||||
let lock = gSettingsService.createLock();
|
||||
lock.get(BAND_SETTING_KEY, this);
|
||||
lock.get(CHANNEL_WIDTH_SETTING_KEY, this);
|
||||
|
||||
this._updateAntennaState();
|
||||
|
||||
let self = this;
|
||||
FMRadio.onantennastatechange = function onantennachange() {
|
||||
self._updateAntennaState();
|
||||
};
|
||||
|
||||
debug("Initialized");
|
||||
},
|
||||
|
||||
// nsISettingsServiceCallback
|
||||
handle: function(aName, aResult) {
|
||||
if (aName == BAND_SETTING_KEY) {
|
||||
this._updateBand(aResult);
|
||||
} else if (aName == CHANNEL_WIDTH_SETTING_KEY) {
|
||||
this._updateChannelWidth(aResult);
|
||||
}
|
||||
},
|
||||
|
||||
handleError: function(aErrorMessage) {
|
||||
this._updateBand(BAND_87500_108000_kHz);
|
||||
this._updateChannelWidth(CHANNEL_WIDTH_100KHZ);
|
||||
},
|
||||
|
||||
_updateAntennaState: function() {
|
||||
let antennaState = FMRadio.isAntennaAvailable;
|
||||
|
||||
if (antennaState != this._antennaAvailable) {
|
||||
this._antennaAvailable = antennaState;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:antennaChange", { });
|
||||
}
|
||||
},
|
||||
|
||||
_updateBand: function(band) {
|
||||
switch (parseInt(band)) {
|
||||
case BAND_87500_108000_kHz:
|
||||
case BAND_76000_108000_kHz:
|
||||
case BAND_76000_90000_kHz:
|
||||
this._currentBand = band;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_updateChannelWidth: function(channelWidth) {
|
||||
switch (parseInt(channelWidth)) {
|
||||
case CHANNEL_WIDTH_50KHZ:
|
||||
case CHANNEL_WIDTH_100KHZ:
|
||||
case CHANNEL_WIDTH_200KHZ:
|
||||
this._currentWidth = channelWidth;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update and cache the current frequency.
|
||||
* Send frequency change message if the frequency is changed.
|
||||
* The returned boolean value indicates if the frequency is changed.
|
||||
*/
|
||||
_updateFrequency: function() {
|
||||
let frequency = FMRadio.frequency;
|
||||
|
||||
if (frequency != this._currentFrequency) {
|
||||
this._currentFrequency = frequency;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:frequencyChange", { });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update and cache the power state of the FM radio.
|
||||
* Send message if the power state is changed.
|
||||
*/
|
||||
_updatePowerState: function() {
|
||||
let enabled = FMRadio.enabled;
|
||||
|
||||
if (this._isEnabled != enabled) {
|
||||
this._isEnabled = enabled;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:powerStateChange", { });
|
||||
|
||||
// If the FM radio is enabled, update the current frequency immediately,
|
||||
if (enabled) {
|
||||
this._updateFrequency();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onSeekComplete: function(success) {
|
||||
if (this._seeking) {
|
||||
this._seeking = false;
|
||||
|
||||
if (this._seekingCallback) {
|
||||
this._seekingCallback(success);
|
||||
this._seekingCallback = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
* Seek the next channel with given direction.
|
||||
* Only one seek action is allowed at once.
|
||||
*/
|
||||
_seekStation: function(direction, aMessage) {
|
||||
let msg = aMessage.json || { };
|
||||
let messageName = aMessage.name + ":Return";
|
||||
|
||||
// If the FM radio is disabled, do not execute the seek action.
|
||||
if(!this._isEnabled) {
|
||||
this._sendMessage(messageName, false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
function callback(success) {
|
||||
debug("Seek completed.");
|
||||
if (!success) {
|
||||
self._sendMessage(messageName, false, null, msg);
|
||||
} else {
|
||||
// Make sure the FM app will get the right frequency.
|
||||
self._updateFrequency();
|
||||
self._sendMessage(messageName, true, null, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._seeking) {
|
||||
// Pass a boolean value to the callback which indicates that
|
||||
// the seek action failed.
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this._seekingCallback = callback;
|
||||
this._seeking = true;
|
||||
|
||||
let self = this;
|
||||
FMRadio.seek(direction);
|
||||
FMRadio.addEventListener("seekcomplete", function FM_onSeekComplete() {
|
||||
FMRadio.removeEventListener("seekcomplete", FM_onSeekComplete);
|
||||
self._onSeekComplete(true);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Round the frequency to match the range of frequency and the channel width.
|
||||
* If the given frequency is out of range, return null.
|
||||
* For example:
|
||||
* - lower: 87.5MHz, upper: 108MHz, channel width: 0.2MHz
|
||||
* 87600 is rounded to 87700
|
||||
* 87580 is rounded to 87500
|
||||
* 109000 is not rounded, null will be returned
|
||||
*/
|
||||
_roundFrequency: function(frequencyInKHz) {
|
||||
if (frequencyInKHz < FM_BANDS[this._currentBand].lower ||
|
||||
frequencyInKHz > FM_BANDS[this._currentBand].upper) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let partToBeRounded = frequencyInKHz - FM_BANDS[this._currentBand].lower;
|
||||
let roundedPart = Math.round(partToBeRounded / this._currentWidth) *
|
||||
this._currentWidth;
|
||||
return FM_BANDS[this._currentBand].lower + roundedPart;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC:
|
||||
this._messages.forEach(function(msgName) {
|
||||
ppmm.removeMessageListener(msgName, this);
|
||||
}.bind(this));
|
||||
|
||||
Services.obs.removeObserver(this, PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC);
|
||||
Services.obs.removeObserver(this, MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC);
|
||||
|
||||
ppmm = null;
|
||||
this._messages = null;
|
||||
break;
|
||||
case MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC:
|
||||
let setting = JSON.parse(aData);
|
||||
this.handleMozSettingsChanged(setting);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_sendMessage: function(message, success, data, msg) {
|
||||
msg.manager.sendAsyncMessage(message + (success ? ":OK" : ":NO"), {
|
||||
data: data,
|
||||
rid: msg.rid,
|
||||
mid: msg.mid
|
||||
});
|
||||
},
|
||||
|
||||
handleMozSettingsChanged: function(settings) {
|
||||
switch (settings.key) {
|
||||
case BAND_SETTING_KEY:
|
||||
this._updateBand(settings.value);
|
||||
break;
|
||||
case CHANNEL_WIDTH_SETTING_KEY:
|
||||
this._updateChannelWidth(settings.value);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_enableFMRadio: function(msg) {
|
||||
let frequencyInKHz = this._roundFrequency(msg.data * 1000);
|
||||
|
||||
// If the FM radio is already enabled or it is currently being enabled
|
||||
// or the given frequency is out of range, return false.
|
||||
if (this._isEnabled || this._enabling || !frequencyInKHz) {
|
||||
this._sendMessage("DOMFMRadio:enable:Return", false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
this._enabling = true;
|
||||
let self = this;
|
||||
|
||||
FMRadio.addEventListener("enabled", function on_enabled() {
|
||||
dump("Perf:FMRadio:Enable " + (Date.now()- timeStart) + " ms.\n");
|
||||
self._enabling = false;
|
||||
|
||||
FMRadio.removeEventListener("enabled", on_enabled);
|
||||
|
||||
// To make sure the FM app will get right frequency after the FM
|
||||
// radio is enabled, we have to set the frequency first.
|
||||
FMRadio.setFrequency(frequencyInKHz);
|
||||
|
||||
// Update the current frequency without sending 'frequencyChange'
|
||||
// msg, to make sure the FM app will get the right frequency when the
|
||||
// 'enabled' event is fired.
|
||||
self._currentFrequency = FMRadio.frequency;
|
||||
|
||||
self._updatePowerState();
|
||||
self._sendMessage("DOMFMRadio:enable:Return", true, null, msg);
|
||||
|
||||
// The frequency is changed from 'null' to some number, so we should
|
||||
// send the 'frequencyChange' message manually.
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:frequencyChange", { });
|
||||
});
|
||||
|
||||
let timeStart = Date.now();
|
||||
|
||||
FMRadio.enable({
|
||||
lowerLimit: FM_BANDS[self._currentBand].lower,
|
||||
upperLimit: FM_BANDS[self._currentBand].upper,
|
||||
channelWidth: self._currentWidth // 100KHz by default
|
||||
});
|
||||
},
|
||||
|
||||
_disableFMRadio: function(msg) {
|
||||
// If the FM radio is already disabled, return false.
|
||||
if (!this._isEnabled) {
|
||||
this._sendMessage("DOMFMRadio:disable:Return", false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
FMRadio.addEventListener("disabled", function on_disabled() {
|
||||
debug("FM Radio is disabled!");
|
||||
FMRadio.removeEventListener("disabled", on_disabled);
|
||||
|
||||
self._updatePowerState();
|
||||
self._sendMessage("DOMFMRadio:disable:Return", true, null, msg);
|
||||
|
||||
// If the FM Radio is currently seeking, no fail-to-seek or similar
|
||||
// event will be fired, execute the seek callback manually.
|
||||
self._onSeekComplete(false);
|
||||
});
|
||||
|
||||
FMRadio.disable();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.json || {};
|
||||
msg.manager = aMessage.target;
|
||||
|
||||
let ret = 0;
|
||||
let self = this;
|
||||
|
||||
if (!aMessage.target.assertPermission("fmradio")) {
|
||||
Cu.reportError("FMRadio message " + aMessage.name +
|
||||
" from a content process with no 'fmradio' privileges.");
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "DOMFMRadio:enable":
|
||||
self._enableFMRadio(msg);
|
||||
break;
|
||||
case "DOMFMRadio:disable":
|
||||
self._disableFMRadio(msg);
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency":
|
||||
let frequencyInKHz = self._roundFrequency(msg.data * 1000);
|
||||
|
||||
// If the FM radio is disabled or the given frequency is out of range,
|
||||
// skip to set frequency and send back the False message immediately.
|
||||
if (!self._isEnabled || !frequencyInKHz) {
|
||||
self._sendMessage("DOMFMRadio:setFrequency:Return", false, null, msg);
|
||||
} else {
|
||||
FMRadio.setFrequency(frequencyInKHz);
|
||||
self._sendMessage("DOMFMRadio:setFrequency:Return", true, null, msg);
|
||||
this._updateFrequency();
|
||||
}
|
||||
break;
|
||||
case "DOMFMRadio:getCurrentBand":
|
||||
// this message is sync
|
||||
return {
|
||||
lower: FM_BANDS[self._currentBand].lower / 1000, // in MHz
|
||||
upper: FM_BANDS[self._currentBand].upper / 1000, // in MHz
|
||||
channelWidth: self._currentWidth / 1000 // in MHz
|
||||
};
|
||||
case "DOMFMRadio:getPowerState":
|
||||
// this message is sync
|
||||
return self._isEnabled;
|
||||
case "DOMFMRadio:getFrequency":
|
||||
// this message is sync
|
||||
return self._isEnabled ? this._currentFrequency / 1000 : null; // in MHz
|
||||
case "DOMFMRadio:getAntennaState":
|
||||
// this message is sync
|
||||
return self._antennaAvailable;
|
||||
case "DOMFMRadio:seekUp":
|
||||
self._seekStation(Ci.nsIFMRadio.SEEK_DIRECTION_UP, aMessage);
|
||||
break;
|
||||
case "DOMFMRadio:seekDown":
|
||||
self._seekStation(Ci.nsIFMRadio.SEEK_DIRECTION_DOWN, aMessage);
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek":
|
||||
// If the FM radio is disabled, or the FM radio is not currently
|
||||
// seeking, do not execute the cancel seek action.
|
||||
if (!self._isEnabled || !self._seeking) {
|
||||
self._sendMessage("DOMFMRadio:cancelSeek:Return", false, null, msg);
|
||||
} else {
|
||||
FMRadio.cancelSeek();
|
||||
// No fail-to-seek or similar event will be fired from the hal part,
|
||||
// so execute the seek callback here manually.
|
||||
this._onSeekComplete(false);
|
||||
// The FM radio will stop at one frequency without any event, so we need to
|
||||
// update the current frequency, make sure the FM app will get the right frequency.
|
||||
this._updateFrequency();
|
||||
self._sendMessage("DOMFMRadio:cancelSeek:Return", true, null, msg);
|
||||
}
|
||||
break;
|
||||
case "DOMFMRadio:updateVisibility":
|
||||
FMRadio.updateVisible(msg == 'visible');
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DOMFMRadioParent.init();
|
||||
|
@ -1,264 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "FMRadio.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsFMRadioSettings.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#undef LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "FMRadio" , ## args)
|
||||
#else
|
||||
#define LOG(args...)
|
||||
#endif
|
||||
|
||||
// The pref indicates if the device has an internal antenna.
|
||||
// If the pref is true, the antanna will be always available.
|
||||
#define DOM_FM_ANTENNA_INTERNAL_PREF "dom.fm.antenna.internal"
|
||||
|
||||
#define RADIO_SEEK_COMPLETE_EVENT_NAME NS_LITERAL_STRING("seekcomplete")
|
||||
#define RADIO_DISABLED_EVENT_NAME NS_LITERAL_STRING("disabled")
|
||||
#define RADIO_ENABLED_EVENT_NAME NS_LITERAL_STRING("enabled")
|
||||
#define ANTENNA_STATE_CHANGED_EVENT_NAME NS_LITERAL_STRING("antennastatechange")
|
||||
|
||||
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
|
||||
|
||||
using namespace mozilla::dom::fm;
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
FMRadio::FMRadio()
|
||||
: mHeadphoneState(SWITCH_STATE_OFF)
|
||||
, mHasInternalAntenna(false)
|
||||
, mHidden(true)
|
||||
{
|
||||
LOG("FMRadio is initialized.");
|
||||
|
||||
mHasInternalAntenna = Preferences::GetBool(DOM_FM_ANTENNA_INTERNAL_PREF,
|
||||
/* default = */ false);
|
||||
if (mHasInternalAntenna) {
|
||||
LOG("We have an internal antenna.");
|
||||
} else {
|
||||
RegisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
mHeadphoneState = GetCurrentSwitchState(SWITCH_HEADPHONES);
|
||||
}
|
||||
|
||||
RegisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
FMRadio::~FMRadio()
|
||||
{
|
||||
UnregisterFMRadioObserver(this);
|
||||
if (!mHasInternalAntenna) {
|
||||
UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
}
|
||||
|
||||
DOMCI_DATA(FMRadio, FMRadio)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(FMRadio)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFMRadio)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FMRadio)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, seekcomplete)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, disabled)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, enabled)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, antennastatechange)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
|
||||
/* readonly attribute boolean isAntennaAvailable; */
|
||||
NS_IMETHODIMP FMRadio::GetIsAntennaAvailable(bool *aIsAvailable)
|
||||
{
|
||||
if (mHasInternalAntenna) {
|
||||
*aIsAvailable = true;
|
||||
} else {
|
||||
*aIsAvailable = mHeadphoneState != SWITCH_STATE_OFF;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute long frequency; */
|
||||
NS_IMETHODIMP FMRadio::GetFrequency(int32_t *aFrequency)
|
||||
{
|
||||
*aFrequency = GetFMRadioFrequency();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute blean enabled; */
|
||||
NS_IMETHODIMP FMRadio::GetEnabled(bool *aEnabled)
|
||||
{
|
||||
*aEnabled = IsFMRadioOn();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void enable (in nsIFMRadioSettings settings); */
|
||||
NS_IMETHODIMP FMRadio::Enable(nsIFMRadioSettings *settings)
|
||||
{
|
||||
hal::FMRadioSettings info;
|
||||
|
||||
int32_t upperLimit, lowerLimit, channelWidth;
|
||||
|
||||
if (!mAudioChannelAgent) {
|
||||
nsresult rv;
|
||||
mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
|
||||
if (!mAudioChannelAgent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, this);
|
||||
}
|
||||
|
||||
bool canPlay;
|
||||
mAudioChannelAgent->SetVisibilityState(!mHidden);
|
||||
mAudioChannelAgent->StartPlaying(&canPlay);
|
||||
|
||||
settings->GetUpperLimit(&upperLimit);
|
||||
settings->GetLowerLimit(&lowerLimit);
|
||||
settings->GetChannelWidth(&channelWidth);
|
||||
|
||||
info.upperLimit() = upperLimit;
|
||||
info.lowerLimit() = lowerLimit;
|
||||
info.spaceType() = channelWidth;
|
||||
|
||||
EnableFMRadio(info);
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(true);
|
||||
// We enable the hardware, but mute the audio stream, in order to
|
||||
// simplify state handling. This is simpler but worse for battery
|
||||
// life; followup is bug 820282.
|
||||
// Note: To adjust FM volume is only available after setting up
|
||||
// routing patch.
|
||||
CanPlayChanged(canPlay);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void disableRadio (); */
|
||||
NS_IMETHODIMP FMRadio::Disable()
|
||||
{
|
||||
// Fix Bug 796733.
|
||||
// DisableFMRadio should be called before SetFmRadioAudioEnabled to prevent
|
||||
// the annoying beep sound.
|
||||
DisableFMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(false);
|
||||
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->StopPlaying();
|
||||
mAudioChannelAgent = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void cancelSeek */
|
||||
NS_IMETHODIMP FMRadio::CancelSeek()
|
||||
{
|
||||
CancelFMRadioSeek();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void seek (in long direction); */
|
||||
NS_IMETHODIMP FMRadio::Seek(int32_t direction)
|
||||
{
|
||||
if (direction == (int)FM_RADIO_SEEK_DIRECTION_UP) {
|
||||
FMRadioSeek(FM_RADIO_SEEK_DIRECTION_UP);
|
||||
} else {
|
||||
FMRadioSeek(FM_RADIO_SEEK_DIRECTION_DOWN);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIFMRadioSettings getSettings (); */
|
||||
NS_IMETHODIMP FMRadio::GetSettings(nsIFMRadioSettings * *_retval)
|
||||
{
|
||||
hal::FMRadioSettings settings;
|
||||
GetFMRadioSettings(&settings);
|
||||
|
||||
nsCOMPtr<nsIFMRadioSettings> radioSettings(new nsFMRadioSettings(
|
||||
settings.upperLimit(),
|
||||
settings.lowerLimit(),
|
||||
settings.spaceType()));
|
||||
radioSettings.forget(_retval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void setFrequency (in long frequency); */
|
||||
NS_IMETHODIMP FMRadio::SetFrequency(int32_t frequency)
|
||||
{
|
||||
SetFMRadioFrequency(frequency);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP FMRadio::UpdateVisible(bool aVisible)
|
||||
{
|
||||
mHidden = !aVisible;
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->SetVisibilityState(!mHidden);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void FMRadio::Notify(const SwitchEvent& aEvent)
|
||||
{
|
||||
if (mHeadphoneState != aEvent.status()) {
|
||||
LOG("Antenna state is changed!");
|
||||
mHeadphoneState = aEvent.status();
|
||||
DispatchTrustedEvent(ANTENNA_STATE_CHANGED_EVENT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
void FMRadio::Notify(const FMRadioOperationInformation& info)
|
||||
{
|
||||
switch (info.operation())
|
||||
{
|
||||
case FM_RADIO_OPERATION_ENABLE:
|
||||
DispatchTrustedEvent(RADIO_ENABLED_EVENT_NAME);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_DISABLE:
|
||||
DispatchTrustedEvent(RADIO_DISABLED_EVENT_NAME);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_SEEK:
|
||||
DispatchTrustedEvent(RADIO_SEEK_COMPLETE_EVENT_NAME);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
/* void canPlayChanged (in boolean canPlay); */
|
||||
NS_IMETHODIMP FMRadio::CanPlayChanged(bool canPlay)
|
||||
{
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
bool AudioEnabled;
|
||||
audioManager->GetFmRadioAudioEnabled(&AudioEnabled);
|
||||
if (AudioEnabled == canPlay) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* mute fm first, it should be better to stop&resume fm */
|
||||
audioManager->SetFmRadioAudioEnabled(canPlay);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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_fm_radio_h__
|
||||
#define mozilla_dom_fm_radio_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsIFMRadio.h"
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
#define NS_FMRADIO_CONTRACTID "@mozilla.org/fmradio;1"
|
||||
// 9cb91834-78a9-4029-b644-7806173c5e2d
|
||||
#define NS_FMRADIO_CID {0x9cb91834, 0x78a9, 0x4029, \
|
||||
{0xb6, 0x44, 0x78, 0x06, 0x17, 0x3c, 0x5e, 0x2d}}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace fm {
|
||||
|
||||
/* Header file */
|
||||
class FMRadio : public nsDOMEventTargetHelper
|
||||
, public nsIFMRadio
|
||||
, public hal::FMRadioObserver
|
||||
, public hal::SwitchObserver
|
||||
, public nsIAudioChannelAgentCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFMRADIO
|
||||
NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
FMRadio();
|
||||
virtual void Notify(const hal::FMRadioOperationInformation& info);
|
||||
virtual void Notify(const hal::SwitchEvent& aEvent);
|
||||
|
||||
private:
|
||||
~FMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
|
||||
hal::SwitchState mHeadphoneState;
|
||||
bool mHasInternalAntenna;
|
||||
bool mHidden;
|
||||
};
|
||||
|
||||
} // namespace fm
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif
|
||||
|
@ -1,31 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMFMRadio.idl',
|
||||
'nsIFMRadio.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_fm'
|
||||
|
||||
MODULE = 'dom'
|
||||
LIBRARY_NAME = 'domfm_s'
|
||||
|
||||
CPP_SOURCES += [
|
||||
'FMRadio.cpp',
|
||||
'nsFMRadioSettings.cpp',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DOMFMRadioParent.jsm',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'DOMFMRadio.manifest',
|
||||
'DOMFMRadioChild.js',
|
||||
]
|
||||
|
||||
LIBXUL_LIBRARY = True
|
@ -1,61 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsFMRadioSettings.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFMRadioSettings, nsIFMRadioSettings)
|
||||
|
||||
nsFMRadioSettings::nsFMRadioSettings(int32_t aUpperLimit,
|
||||
int32_t aLowerLimit,
|
||||
int32_t aChannelWidth)
|
||||
{
|
||||
mUpperLimit = aUpperLimit;
|
||||
mLowerLimit = aLowerLimit;
|
||||
mChannelWidth = aChannelWidth;
|
||||
}
|
||||
|
||||
nsFMRadioSettings::~nsFMRadioSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* attribute long upperLimit; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetUpperLimit(int32_t *aUpperLimit)
|
||||
{
|
||||
*aUpperLimit = mUpperLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetUpperLimit(int32_t aUpperLimit)
|
||||
{
|
||||
mUpperLimit = aUpperLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute long lowerLimit; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetLowerLimit(int32_t *aLowerLimit)
|
||||
{
|
||||
*aLowerLimit = mLowerLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetLowerLimit(int32_t aLowerLimit)
|
||||
{
|
||||
mLowerLimit = aLowerLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute long spaceType; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetChannelWidth(int32_t *aChannelWidth)
|
||||
{
|
||||
*aChannelWidth = mChannelWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetChannelWidth(int32_t aChannelWidth)
|
||||
{
|
||||
mChannelWidth = aChannelWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* 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_fm_radio_settings_h__
|
||||
#define mozilla_dom_fm_radio_settings_h__
|
||||
|
||||
#include "nsIFMRadio.h"
|
||||
|
||||
class nsFMRadioSettings : public nsIFMRadioSettings
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFMRADIOSETTINGS
|
||||
|
||||
nsFMRadioSettings(int32_t aUpperLimit, int32_t aLowerLimit, int32_t aChannelWidth);
|
||||
private:
|
||||
~nsFMRadioSettings();
|
||||
int32_t mUpperLimit;
|
||||
int32_t mLowerLimit;
|
||||
int32_t mChannelWidth;
|
||||
};
|
||||
#endif
|
||||
|
@ -1,122 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMDOMRequest.idl"
|
||||
|
||||
[scriptable, uuid(1d0443f3-ac30-4f9e-a070-002bb20ce1e6)]
|
||||
interface nsIDOMFMRadio : nsISupports {
|
||||
/* Indicates if the FM radio is enabled. */
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/* Indicates if the antenna is plugged and available. */
|
||||
readonly attribute boolean antennaAvailable;
|
||||
|
||||
/**
|
||||
* Current frequency in MHz.
|
||||
* The value will be null if the FM radio is disabled.
|
||||
*/
|
||||
readonly attribute jsval frequency;
|
||||
|
||||
/* The upper bound of frequency in MHz. */
|
||||
readonly attribute double frequencyUpperBound;
|
||||
|
||||
/* The lower bound of frequency in MHz. */
|
||||
readonly attribute double frequencyLowerBound;
|
||||
|
||||
/**
|
||||
* The channel width of the ranges of frequency, in MHz.
|
||||
* Usually, the value is one of:
|
||||
* - 0.05 MHz
|
||||
* - 0.1 MHz
|
||||
* - 0.2 MHz
|
||||
*/
|
||||
readonly attribute double channelWidth;
|
||||
|
||||
/* Fired when the FM radio is enabled. */
|
||||
attribute nsIDOMEventListener onenabled;
|
||||
|
||||
/* Fired when the FM radio is disabled. */
|
||||
attribute nsIDOMEventListener ondisabled;
|
||||
|
||||
/**
|
||||
* Fired when the antenna becomes available or unavailable, i.e., fired when
|
||||
* the antennaAvailable attribute changes.
|
||||
*/
|
||||
attribute nsIDOMEventListener onantennaavailablechange;
|
||||
|
||||
/* Fired when the FM radio's frequency is changed. */
|
||||
attribute nsIDOMEventListener onfrequencychange;
|
||||
|
||||
/**
|
||||
* Power the FM radio off.
|
||||
* The disabled event will be fired if this request completes successfully.
|
||||
*/
|
||||
nsIDOMDOMRequest disable();
|
||||
|
||||
/**
|
||||
* Power the FM radio on, and tune the radio to the given frequency in MHz.
|
||||
* This will fail if the given frequency is out of range.
|
||||
* The enabled event and frequencychange event will be fired if this request
|
||||
* completes successfully.
|
||||
*/
|
||||
nsIDOMDOMRequest enable(in double frequency);
|
||||
|
||||
/**
|
||||
* Tune the FM radio to the given frequency.
|
||||
* This will fail if the given frequency is out of range.
|
||||
*
|
||||
* Note that the FM radio may not tuned to the exact frequency given. To get
|
||||
* the frequency the radio is actually tuned to, wait for the request to fire
|
||||
* onsucess (or wait for the frequencychange event to fire), and then read the
|
||||
* frequency attribute.
|
||||
*/
|
||||
nsIDOMDOMRequest setFrequency(in double frequency);
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek up to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once:
|
||||
* If the radio is seeking when the seekUp is called, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest seekUp();
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek down to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once:
|
||||
* If the radio is seeking when the seekDown is called, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest seekDown();
|
||||
|
||||
/**
|
||||
* Cancel the seek action.
|
||||
* If the radio is not currently seeking up or down, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest cancelSeek();
|
||||
|
||||
|
||||
/**
|
||||
* These functions related to EventTarget are temporary hacks:
|
||||
* - addEventListener
|
||||
* - removeEventListener
|
||||
* - handleEvent
|
||||
*
|
||||
* These will be removed by inheriting from nsIJSDOMEventTarget,
|
||||
* see bug 731746.
|
||||
*/
|
||||
[optional_argc] void addEventListener(in DOMString type,
|
||||
in nsIDOMEventListener listener,
|
||||
[optional] in boolean useCapture,
|
||||
[optional] in boolean wantsUntrusted);
|
||||
|
||||
void removeEventListener(in DOMString type,
|
||||
in nsIDOMEventListener listener,
|
||||
[optional] in boolean useCapture);
|
||||
|
||||
boolean dispatchEvent(in nsIDOMEvent evt) raises(DOMException);
|
||||
};
|
||||
|
@ -1,107 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
[scriptable, uuid(c142387a-5488-454b-8b5a-91f0dbee833b)]
|
||||
interface nsIFMRadioSettings : nsISupports
|
||||
{
|
||||
/* Upper limit in KHz */
|
||||
attribute long upperLimit;
|
||||
/* Lower limit in KHz */
|
||||
attribute long lowerLimit;
|
||||
/* Channel width in KHz */
|
||||
attribute long channelWidth;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an interface to expose the FM radio hardware related functions;
|
||||
* it's kind of the FM radio hardware wrapper interface.
|
||||
*
|
||||
* Because the WebFM API (navigator.mozFMRadio) is implemented as a JS component,
|
||||
* it can't access our C++ hardware interface directly; instead it must go
|
||||
* through this interface.
|
||||
* Do not confuse this interface with the WebFM DOM interface (nsIDOMFMRadio).
|
||||
*
|
||||
* If the WebFM API is re-written in c++ some day, this interface will be useless.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(2ee7c122-b7aa-4948-9bc5-e4593ed4ac32)]
|
||||
interface nsIFMRadio : nsIDOMEventTarget {
|
||||
const long SEEK_DIRECTION_UP = 0;
|
||||
const long SEEK_DIRECTION_DOWN = 1;
|
||||
|
||||
/**
|
||||
* Indicates if the FM radio hardware is enabled.
|
||||
*/
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/**
|
||||
* Current frequency in KHz
|
||||
*/
|
||||
readonly attribute long frequency;
|
||||
|
||||
/**
|
||||
* Indicates if the antenna is plugged in and available.
|
||||
*/
|
||||
readonly attribute boolean isAntennaAvailable;
|
||||
|
||||
/**
|
||||
* Enable the FM radio hardware with the given settings.
|
||||
*/
|
||||
void enable(in nsIFMRadioSettings settings);
|
||||
|
||||
/**
|
||||
* Disable the FM radio hardware.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
/**
|
||||
* Seek the next available channel (up or down).
|
||||
*
|
||||
* @param direction
|
||||
* The value should be one of SEEK_DIRECTION_DOWN and SEEK_DIRECTION_UP
|
||||
*/
|
||||
void seek(in long direction);
|
||||
|
||||
/**
|
||||
* Cancel the seek action.
|
||||
*/
|
||||
void cancelSeek();
|
||||
|
||||
/**
|
||||
* Get the current settings.
|
||||
*/
|
||||
nsIFMRadioSettings getSettings();
|
||||
|
||||
/**
|
||||
* Set the frequency in KHz
|
||||
*/
|
||||
void setFrequency(in long frequency);
|
||||
|
||||
/**
|
||||
* Update the visibility state of our client.
|
||||
*/
|
||||
void updateVisible(in boolean visible);
|
||||
|
||||
/**
|
||||
* Fired when the antenna state is changed.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onantennastatechange;
|
||||
|
||||
/**
|
||||
* Fired when a seek action completes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onseekcomplete;
|
||||
|
||||
/**
|
||||
* Fired when the FM radio hardware is enabled.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onenabled;
|
||||
|
||||
/**
|
||||
* Fired when the FM radio hardware is disabled.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval ondisabled;
|
||||
};
|
||||
|
295
dom/fmradio/FMRadio.cpp
Normal file
295
dom/fmradio/FMRadio.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include "mozilla/dom/FMRadio.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/FMRadioBinding.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/dom/FMRadioService.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args...) FM_LOG("FMRadio", args)
|
||||
|
||||
// The pref indicates if the device has an internal antenna.
|
||||
// If the pref is true, the antanna will be always available.
|
||||
#define DOM_FM_ANTENNA_INTERNAL_PREF "dom.fmradio.antenna.internal"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class FMRadioRequest MOZ_FINAL : public ReplyRunnable
|
||||
, public DOMRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio)
|
||||
: DOMRequest(aWindow)
|
||||
{
|
||||
// |FMRadio| inherits from |nsIDOMEventTarget| and |nsISupportsWeakReference|
|
||||
// which both inherits from nsISupports, so |nsISupports| is an ambiguous
|
||||
// base of |FMRadio|, we have to cast |aFMRadio| to one of the base classes.
|
||||
mFMRadio = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aFMRadio));
|
||||
}
|
||||
|
||||
~FMRadioRequest() { }
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mFMRadio);
|
||||
if (!target) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FMRadio* fmRadio = static_cast<FMRadio*>(
|
||||
static_cast<nsIDOMEventTarget*>(target));
|
||||
|
||||
if (fmRadio->mIsShutdown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (mResponseType.type()) {
|
||||
case FMRadioResponseType::TErrorResponse:
|
||||
FireError(mResponseType.get_ErrorResponse().error());
|
||||
break;
|
||||
case FMRadioResponseType::TSuccessResponse:
|
||||
FireSuccess(JS::UndefinedHandleValue);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsWeakPtr mFMRadio;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest)
|
||||
|
||||
FMRadio::FMRadio()
|
||||
: mHeadphoneState(SWITCH_STATE_OFF)
|
||||
, mHasInternalAntenna(false)
|
||||
, mIsShutdown(false)
|
||||
{
|
||||
LOG("FMRadio is initialized.");
|
||||
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
FMRadio::~FMRadio()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Init(nsPIDOMWindow *aWindow)
|
||||
{
|
||||
BindToOwner(aWindow);
|
||||
|
||||
IFMRadioService::Singleton()->AddObserver(this);
|
||||
|
||||
mHasInternalAntenna = Preferences::GetBool(DOM_FM_ANTENNA_INTERNAL_PREF,
|
||||
/* default = */ false);
|
||||
if (mHasInternalAntenna) {
|
||||
LOG("We have an internal antenna.");
|
||||
} else {
|
||||
mHeadphoneState = GetCurrentSwitchState(SWITCH_HEADPHONES);
|
||||
RegisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Shutdown()
|
||||
{
|
||||
IFMRadioService::Singleton()->RemoveObserver(this);
|
||||
|
||||
if (!mHasInternalAntenna) {
|
||||
UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
|
||||
mIsShutdown = true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
FMRadio::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return FMRadioBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Notify(const SwitchEvent& aEvent)
|
||||
{
|
||||
MOZ_ASSERT(!mHasInternalAntenna);
|
||||
|
||||
if (mHeadphoneState != aEvent.status()) {
|
||||
mHeadphoneState = aEvent.status();
|
||||
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("antennaavailablechange"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Notify(const FMRadioEventType& aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case FrequencyChanged:
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("frequencychange"));
|
||||
break;
|
||||
case EnabledChanged:
|
||||
if (Enabled()) {
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("enabled"));
|
||||
} else {
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
FMRadio::Enabled()
|
||||
{
|
||||
return IFMRadioService::Singleton()->IsEnabled();
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadio::AntennaAvailable() const
|
||||
{
|
||||
return mHasInternalAntenna ? true : mHeadphoneState != SWITCH_STATE_OFF;
|
||||
}
|
||||
|
||||
Nullable<double>
|
||||
FMRadio::GetFrequency() const
|
||||
{
|
||||
return Enabled() ?
|
||||
Nullable<double>(IFMRadioService::Singleton()->GetFrequency()) :
|
||||
Nullable<double>();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::FrequencyUpperBound() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetFrequencyUpperBound();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::FrequencyLowerBound() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetFrequencyLowerBound();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::ChannelWidth() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetChannelWidth();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::Enable(double aFrequency)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Enable(aFrequency, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::Disable()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Disable(r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SetFrequency(double aFrequency)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->SetFrequency(aFrequency, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SeekUp()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_UP, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SeekDown()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_DOWN, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::CancelSeek()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->CancelSeek(r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
92
dom/fmradio/FMRadio.h
Normal file
92
dom/fmradio/FMRadio.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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_FMRadio_h
|
||||
#define mozilla_dom_FMRadio_h
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
class nsIScriptContext;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class DOMRequest;
|
||||
|
||||
class FMRadio MOZ_FINAL : public nsDOMEventTargetHelper
|
||||
, public hal::SwitchObserver
|
||||
, public FMRadioEventObserver
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
friend class FMRadioRequest;
|
||||
|
||||
public:
|
||||
FMRadio();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
void Init(nsPIDOMWindow *aWindow);
|
||||
void Shutdown();
|
||||
|
||||
/* hal::SwitchObserver */
|
||||
virtual void Notify(const hal::SwitchEvent& aEvent) MOZ_OVERRIDE;
|
||||
/* FMRadioEventObserver */
|
||||
virtual void Notify(const FMRadioEventType& aType) MOZ_OVERRIDE;
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
static bool Enabled();
|
||||
|
||||
bool AntennaAvailable() const;
|
||||
|
||||
Nullable<double> GetFrequency() const;
|
||||
|
||||
double FrequencyUpperBound() const;
|
||||
|
||||
double FrequencyLowerBound() const;
|
||||
|
||||
double ChannelWidth() const;
|
||||
|
||||
already_AddRefed<DOMRequest> Enable(double aFrequency);
|
||||
|
||||
already_AddRefed<DOMRequest> Disable();
|
||||
|
||||
already_AddRefed<DOMRequest> SetFrequency(double aFrequency);
|
||||
|
||||
already_AddRefed<DOMRequest> SeekUp();
|
||||
|
||||
already_AddRefed<DOMRequest> SeekDown();
|
||||
|
||||
already_AddRefed<DOMRequest> CancelSeek();
|
||||
|
||||
IMPL_EVENT_HANDLER(enabled);
|
||||
IMPL_EVENT_HANDLER(disabled);
|
||||
IMPL_EVENT_HANDLER(antennaavailablechange);
|
||||
IMPL_EVENT_HANDLER(frequencychange);
|
||||
|
||||
private:
|
||||
~FMRadio();
|
||||
|
||||
hal::SwitchState mHeadphoneState;
|
||||
bool mHasInternalAntenna;
|
||||
bool mIsShutdown;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_FMRadio_h
|
||||
|
42
dom/fmradio/FMRadioCommon.h
Normal file
42
dom/fmradio/FMRadioCommon.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 FMRADIOCOMMON_H_
|
||||
#define FMRADIOCOMMON_H_
|
||||
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
#undef FM_LOG
|
||||
#if defined(ANDROID)
|
||||
#include <android/log.h>
|
||||
#define FM_LOG(FMRADIO_LOG_INFO, args...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, \
|
||||
FMRADIO_LOG_INFO, \
|
||||
## args)
|
||||
#else
|
||||
#define FM_LOG(args...)
|
||||
#endif
|
||||
|
||||
#define BEGIN_FMRADIO_NAMESPACE \
|
||||
namespace mozilla { namespace dom {
|
||||
#define END_FMRADIO_NAMESPACE \
|
||||
} /* namespace dom */ } /* namespace mozilla */
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
enum FMRadioEventType
|
||||
{
|
||||
FrequencyChanged,
|
||||
EnabledChanged
|
||||
};
|
||||
|
||||
typedef mozilla::Observer<FMRadioEventType> FMRadioEventObserver;
|
||||
typedef mozilla::ObserverList<FMRadioEventType> FMRadioEventObserverList;
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif /* FMRADIOCOMMON_H_ */
|
||||
|
800
dom/fmradio/FMRadioService.cpp
Normal file
800
dom/fmradio/FMRadioService.cpp
Normal file
@ -0,0 +1,800 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "FMRadioService.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "AudioManager.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/FMRadioChild.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISettingsService.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
#define BAND_87500_108000_kHz 1
|
||||
#define BAND_76000_108000_kHz 2
|
||||
#define BAND_76000_90000_kHz 3
|
||||
|
||||
#define CHANNEL_WIDTH_200KHZ 200
|
||||
#define CHANNEL_WIDTH_100KHZ 100
|
||||
#define CHANNEL_WIDTH_50KHZ 50
|
||||
|
||||
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
|
||||
#define SETTING_KEY_RIL_RADIO_DISABLED "ril.radio.disabled"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
// static
|
||||
IFMRadioService*
|
||||
IFMRadioService::Singleton()
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return FMRadioChild::Singleton();
|
||||
} else {
|
||||
return FMRadioService::Singleton();
|
||||
}
|
||||
}
|
||||
|
||||
StaticRefPtr<FMRadioService> FMRadioService::sFMRadioService;
|
||||
|
||||
FMRadioService::FMRadioService()
|
||||
: mPendingFrequencyInKHz(0)
|
||||
, mState(Disabled)
|
||||
, mHasReadRilSetting(false)
|
||||
, mRilDisabled(false)
|
||||
, mPendingRequest(nullptr)
|
||||
, mObserverList(FMRadioEventObserverList())
|
||||
{
|
||||
|
||||
// Read power state and frequency from Hal.
|
||||
mEnabled = IsFMRadioOn();
|
||||
if (mEnabled) {
|
||||
mPendingFrequencyInKHz = GetFMRadioFrequency();
|
||||
SetState(Enabled);
|
||||
}
|
||||
|
||||
switch (Preferences::GetInt("dom.fmradio.band", BAND_87500_108000_kHz)) {
|
||||
case BAND_76000_90000_kHz:
|
||||
mUpperBoundInKHz = 90000;
|
||||
mLowerBoundInKHz = 76000;
|
||||
break;
|
||||
case BAND_76000_108000_kHz:
|
||||
mUpperBoundInKHz = 108000;
|
||||
mLowerBoundInKHz = 76000;
|
||||
break;
|
||||
case BAND_87500_108000_kHz:
|
||||
default:
|
||||
mUpperBoundInKHz = 108000;
|
||||
mLowerBoundInKHz = 87500;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Preferences::GetInt("dom.fmradio.channelWidth",
|
||||
CHANNEL_WIDTH_100KHZ)) {
|
||||
case CHANNEL_WIDTH_200KHZ:
|
||||
mChannelWidthInKHz = 200;
|
||||
break;
|
||||
case CHANNEL_WIDTH_50KHZ:
|
||||
mChannelWidthInKHz = 50;
|
||||
break;
|
||||
case CHANNEL_WIDTH_100KHZ:
|
||||
default:
|
||||
mChannelWidthInKHz = 100;
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
|
||||
if (NS_FAILED(obs->AddObserver(this,
|
||||
MOZSETTINGS_CHANGED_ID,
|
||||
/* useWeak */ false))) {
|
||||
NS_WARNING("Failed to add settings change observer!");
|
||||
}
|
||||
|
||||
RegisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
FMRadioService::~FMRadioService()
|
||||
{
|
||||
UnregisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
class EnableRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
EnableRunnable(int32_t aUpperLimit, int32_t aLowerLimit, int32_t aSpaceType)
|
||||
: mUpperLimit(aUpperLimit)
|
||||
, mLowerLimit(aLowerLimit)
|
||||
, mSpaceType(aSpaceType) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
FMRadioSettings info;
|
||||
info.upperLimit() = mUpperLimit;
|
||||
info.lowerLimit() = mLowerLimit;
|
||||
info.spaceType() = mSpaceType;
|
||||
|
||||
EnableFMRadio(info);
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
audioManager->SetFmRadioAudioEnabled(true);
|
||||
|
||||
// TODO apply path from bug 862899: AudioChannelAgent per process
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mUpperLimit;
|
||||
int32_t mLowerLimit;
|
||||
int32_t mSpaceType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the airplane-mode setting, if the airplane-mode is not enabled, we
|
||||
* enable the FM radio.
|
||||
*/
|
||||
class ReadRilSettingTask MOZ_FINAL : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ReadRilSettingTask(nsRefPtr<ReplyRunnable> aPendingRequest)
|
||||
: mPendingRequest(aPendingRequest) { }
|
||||
|
||||
NS_IMETHOD
|
||||
Handle(const nsAString& aName, const JS::Value& aResult)
|
||||
{
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
MOZ_ASSERT(mPendingRequest == fmRadioService->mPendingRequest);
|
||||
|
||||
fmRadioService->mHasReadRilSetting = true;
|
||||
|
||||
if (!aResult.isBoolean()) {
|
||||
// Failed to read the setting value, set the state back to Disabled.
|
||||
fmRadioService->TransitionState(
|
||||
ErrorResponse(NS_LITERAL_STRING("Unexpected error")), Disabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
fmRadioService->mRilDisabled = aResult.toBoolean();
|
||||
if (!fmRadioService->mRilDisabled) {
|
||||
EnableRunnable* runnable =
|
||||
new EnableRunnable(fmRadioService->mUpperBoundInKHz,
|
||||
fmRadioService->mLowerBoundInKHz,
|
||||
fmRadioService->mChannelWidthInKHz);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
} else {
|
||||
// Airplane mode is enabled, set the state back to Disabled.
|
||||
fmRadioService->TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Airplane mode currently enabled")), Disabled);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
HandleError(const nsAString& aName)
|
||||
{
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
MOZ_ASSERT(mPendingRequest == fmRadioService->mPendingRequest);
|
||||
|
||||
fmRadioService->TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Unexpected error")), Disabled);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ReplyRunnable> mPendingRequest;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ReadRilSettingTask, nsISettingsServiceCallback)
|
||||
|
||||
class DisableRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DisableRunnable() { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
// Fix Bug 796733. DisableFMRadio should be called before
|
||||
// SetFmRadioAudioEnabled to prevent the annoying beep sound.
|
||||
DisableFMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class SetFrequencyRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SetFrequencyRunnable(int32_t aFrequency)
|
||||
: mFrequency(aFrequency) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
SetFMRadioFrequency(mFrequency);
|
||||
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
fmRadioService->UpdateFrequency();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mFrequency;
|
||||
};
|
||||
|
||||
class SeekRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SeekRunnable(FMRadioSeekDirection aDirection) : mDirection(aDirection) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
switch (mDirection) {
|
||||
case FM_RADIO_SEEK_DIRECTION_UP:
|
||||
case FM_RADIO_SEEK_DIRECTION_DOWN:
|
||||
FMRadioSeek(mDirection);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
FMRadioSeekDirection mDirection;
|
||||
};
|
||||
|
||||
void
|
||||
FMRadioService::TransitionState(const FMRadioResponseType& aResponse,
|
||||
FMRadioState aState)
|
||||
{
|
||||
if (mPendingRequest) {
|
||||
mPendingRequest->SetReply(aResponse);
|
||||
NS_DispatchToMainThread(mPendingRequest);
|
||||
}
|
||||
|
||||
SetState(aState);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::SetState(FMRadioState aState)
|
||||
{
|
||||
mState = aState;
|
||||
mPendingRequest = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::AddObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
mObserverList.AddObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::RemoveObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
mObserverList.RemoveObserver(aObserver);
|
||||
|
||||
if (mObserverList.Length() == 0)
|
||||
{
|
||||
// Turning off the FM radio HW because observer list is empty.
|
||||
if (IsFMRadioOn()) {
|
||||
NS_DispatchToMainThread(new DisableRunnable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the frequency to match the range of frequency and the channel width. If
|
||||
* the given frequency is out of range, return 0. For example:
|
||||
* - lower: 87500KHz, upper: 108000KHz, channel width: 200KHz
|
||||
* 87.6MHz is rounded to 87700KHz
|
||||
* 87.58MHz is rounded to 87500KHz
|
||||
* 87.49MHz is rounded to 87500KHz
|
||||
* 109MHz is not rounded, 0 will be returned
|
||||
*
|
||||
* We take frequency in MHz to prevent precision losing, and return rounded
|
||||
* value in KHz for Gonk using.
|
||||
*/
|
||||
int32_t
|
||||
FMRadioService::RoundFrequency(double aFrequencyInMHz)
|
||||
{
|
||||
double halfChannelWidthInMHz = mChannelWidthInKHz / 1000.0 / 2;
|
||||
|
||||
// Make sure 87.49999MHz would be rounded to the lower bound when
|
||||
// the lower bound is 87500KHz.
|
||||
if (aFrequencyInMHz < mLowerBoundInKHz / 1000.0 - halfChannelWidthInMHz ||
|
||||
aFrequencyInMHz > mUpperBoundInKHz / 1000.0 + halfChannelWidthInMHz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t partToBeRounded = round(aFrequencyInMHz * 1000) - mLowerBoundInKHz;
|
||||
int32_t roundedPart = round(partToBeRounded / (double)mChannelWidthInKHz) *
|
||||
mChannelWidthInKHz;
|
||||
|
||||
return mLowerBoundInKHz + roundedPart;
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioService::IsEnabled() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return IsFMRadioOn();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequency() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
if (IsEnabled()) {
|
||||
int32_t frequencyInKHz = GetFMRadioFrequency();
|
||||
return frequencyInKHz / 1000.0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequencyUpperBound() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mUpperBoundInKHz / 1000.0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequencyLowerBound() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mLowerBoundInKHz / 1000.0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetChannelWidth() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mChannelWidthInKHz / 1000.0;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Enable(double aFrequencyInMHz, ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Seeking:
|
||||
case Enabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabled:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t roundedFrequency = RoundFrequency(aFrequencyInMHz);
|
||||
|
||||
if (!roundedFrequency) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Frequency is out of range")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHasReadRilSetting && mRilDisabled) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Airplane mode currently enabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
SetState(Enabling);
|
||||
// Cache the enable request just in case disable() is called
|
||||
// while the FM radio HW is being enabled.
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
// Cache the frequency value, and set it after the FM radio HW is enabled
|
||||
mPendingFrequencyInKHz = roundedFrequency;
|
||||
|
||||
if (!mHasReadRilSetting) {
|
||||
nsCOMPtr<nsISettingsService> settings =
|
||||
do_GetService("@mozilla.org/settingsService;1");
|
||||
|
||||
nsCOMPtr<nsISettingsServiceLock> settingsLock;
|
||||
nsresult rv = settings->CreateLock(getter_AddRefs(settingsLock));
|
||||
if (NS_FAILED(rv)) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Can't create settings lock")), Disabled);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ReadRilSettingTask> callback =
|
||||
new ReadRilSettingTask(mPendingRequest);
|
||||
|
||||
rv = settingsLock->Get(SETTING_KEY_RIL_RADIO_DISABLED, callback);
|
||||
if (NS_FAILED(rv)) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Can't get settings lock")), Disabled);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new EnableRunnable(mUpperBoundInKHz,
|
||||
mLowerBoundInKHz,
|
||||
mChannelWidthInKHz));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Disable(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
// When airplane-mode is enabled, we will call this function from
|
||||
// FMRadioService::Observe without passing a ReplyRunnable, so we have to
|
||||
// check if |aReplyRunnable| is null before we dispatch it.
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
switch (mState) {
|
||||
case Disabling:
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
return;
|
||||
case Disabled:
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
return;
|
||||
case Enabled:
|
||||
case Enabling:
|
||||
case Seeking:
|
||||
break;
|
||||
}
|
||||
|
||||
nsRefPtr<ReplyRunnable> enablingRequest = mPendingRequest;
|
||||
|
||||
// If the FM Radio is currently seeking, no fail-to-seek or similar
|
||||
// event will be fired, execute the seek callback manually.
|
||||
if (mState == Seeking) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Seek action is cancelled")), Disabling);
|
||||
}
|
||||
|
||||
FMRadioState preState = mState;
|
||||
SetState(Disabling);
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
if (preState == Enabling) {
|
||||
// If the radio is currently enabling, we fire the error callback on the
|
||||
// enable request immediately. When the radio finishes enabling, we'll call
|
||||
// DoDisable and fire the success callback on the disable request.
|
||||
enablingRequest->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("Enable action is cancelled")));
|
||||
NS_DispatchToMainThread(enablingRequest);
|
||||
|
||||
// If we haven't read the ril settings yet we won't enable the FM radio HW,
|
||||
// so fail the disable request immediately.
|
||||
if (!mHasReadRilSetting) {
|
||||
SetState(Disabled);
|
||||
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DoDisable();
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::DoDisable()
|
||||
{
|
||||
// To make such codes work:
|
||||
// navigator.mozFMRadio.disable();
|
||||
// navigator.mozFMRadio.ondisabled = function() {
|
||||
// console.log("We will catch disabled event ");
|
||||
// };
|
||||
// we need to call hal::DisableFMRadio() asynchronously. Same reason for
|
||||
// EnableRunnable and SetFrequencyRunnable.
|
||||
NS_DispatchToMainThread(new DisableRunnable());
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::SetFrequency(double aFrequencyInMHz,
|
||||
ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Disabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Seeking:
|
||||
CancelFMRadioSeek();
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
|
||||
break;
|
||||
case Enabled:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t roundedFrequency = RoundFrequency(aFrequencyInMHz);
|
||||
|
||||
if (!roundedFrequency) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Frequency is out of range")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new SetFrequencyRunnable(roundedFrequency));
|
||||
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Seek(FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Seeking:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently seeking")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabled:
|
||||
break;
|
||||
}
|
||||
|
||||
SetState(Seeking);
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
NS_DispatchToMainThread(new SeekRunnable(aDirection));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::CancelSeek(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
// We accept canceling seek request only if it's currently seeking.
|
||||
if (mState != Seeking) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently not seeking")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel the seek immediately to prevent it from completing.
|
||||
CancelFMRadioSeek();
|
||||
|
||||
TransitionState(
|
||||
ErrorResponse(NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
|
||||
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FMRadioService::Observe(nsISupports * aSubject,
|
||||
const char * aTopic,
|
||||
const PRUnichar * aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(sFMRadioService);
|
||||
|
||||
if (strcmp(aTopic, MOZSETTINGS_CHANGED_ID) != 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The string that we're interested in will be a JSON string looks like:
|
||||
// {"key":"ril.radio.disabled","value":true}
|
||||
AutoSafeJSContext cx;
|
||||
const nsDependentString dataStr(aData);
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
|
||||
!val.isObject()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject& obj(val.toObject());
|
||||
JS::Rooted<JS::Value> key(cx);
|
||||
if (!JS_GetProperty(cx, &obj, "key", &key) ||
|
||||
!key.isString()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSString*> jsKey(cx, key.toString());
|
||||
nsDependentJSString keyStr;
|
||||
if (!keyStr.init(cx, jsKey)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!JS_GetProperty(cx, &obj, "value", &value)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (keyStr.EqualsLiteral(SETTING_KEY_RIL_RADIO_DISABLED)) {
|
||||
if (!value.isBoolean()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mRilDisabled = value.toBoolean();
|
||||
mHasReadRilSetting = true;
|
||||
|
||||
// Disable the FM radio HW if Airplane mode is enabled.
|
||||
if (mRilDisabled) {
|
||||
Disable(nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::NotifyFMRadioEvent(FMRadioEventType aType)
|
||||
{
|
||||
mObserverList.Broadcast(aType);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Notify(const FMRadioOperationInformation& aInfo)
|
||||
{
|
||||
switch (aInfo.operation()) {
|
||||
case FM_RADIO_OPERATION_ENABLE:
|
||||
MOZ_ASSERT(IsFMRadioOn());
|
||||
MOZ_ASSERT(mState == Disabling || mState == Enabling);
|
||||
|
||||
// If we're disabling, disable the radio right now.
|
||||
if (mState == Disabling) {
|
||||
DoDisable();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire success callback on the enable request.
|
||||
TransitionState(SuccessResponse(), Enabled);
|
||||
|
||||
// To make sure the FM app will get the right frequency after the FM
|
||||
// radio is enabled, we have to set the frequency first.
|
||||
SetFMRadioFrequency(mPendingFrequencyInKHz);
|
||||
|
||||
// Update the current frequency without sending the`FrequencyChanged`
|
||||
// event, to make sure the FM app will get the right frequency when the
|
||||
// `EnabledChange` event is sent.
|
||||
mPendingFrequencyInKHz = GetFMRadioFrequency();
|
||||
UpdatePowerState();
|
||||
|
||||
// The frequency was changed from '0' to some meaningful number, so we
|
||||
// should send the `FrequencyChanged` event manually.
|
||||
NotifyFMRadioEvent(FrequencyChanged);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_DISABLE:
|
||||
MOZ_ASSERT(mState == Disabling);
|
||||
|
||||
TransitionState(SuccessResponse(), Disabled);
|
||||
UpdatePowerState();
|
||||
break;
|
||||
case FM_RADIO_OPERATION_SEEK:
|
||||
|
||||
// Seek action might be cancelled by SetFrequency(), we need to check if
|
||||
// the current state is Seeking.
|
||||
if (mState == Seeking) {
|
||||
TransitionState(SuccessResponse(), Enabled);
|
||||
}
|
||||
|
||||
UpdateFrequency();
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::UpdatePowerState()
|
||||
{
|
||||
bool enabled = IsFMRadioOn();
|
||||
if (enabled != mEnabled) {
|
||||
mEnabled = enabled;
|
||||
NotifyFMRadioEvent(EnabledChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::UpdateFrequency()
|
||||
{
|
||||
int32_t frequency = GetFMRadioFrequency();
|
||||
if (mPendingFrequencyInKHz != frequency) {
|
||||
mPendingFrequencyInKHz = frequency;
|
||||
NotifyFMRadioEvent(FrequencyChanged);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
FMRadioService*
|
||||
FMRadioService::Singleton()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sFMRadioService) {
|
||||
sFMRadioService = new FMRadioService();
|
||||
}
|
||||
|
||||
return sFMRadioService;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(FMRadioService, nsIObserver)
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
207
dom/fmradio/FMRadioService.h
Normal file
207
dom/fmradio/FMRadioService.h
Normal file
@ -0,0 +1,207 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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_fmradioservice_h__
|
||||
#define mozilla_dom_fmradioservice_h__
|
||||
|
||||
#include "mozilla/dom/PFMRadioRequest.h"
|
||||
#include "FMRadioCommon.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class ReplyRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReplyRunnable() : mResponseType(SuccessResponse()) {}
|
||||
virtual ~ReplyRunnable() {}
|
||||
|
||||
void
|
||||
SetReply(const FMRadioResponseType& aResponseType)
|
||||
{
|
||||
mResponseType = aResponseType;
|
||||
}
|
||||
|
||||
protected:
|
||||
FMRadioResponseType mResponseType;
|
||||
};
|
||||
|
||||
/**
|
||||
* The FMRadio Service Interface for FMRadio.
|
||||
*
|
||||
* There are two concrete classes which implement this interface:
|
||||
* - FMRadioService
|
||||
* It's used in the main process, implements all the logics about FM Radio.
|
||||
*
|
||||
* - FMRadioChild
|
||||
* It's used in subprocess. It's a kind of proxy which just sends all
|
||||
* the requests to main process through IPC channel.
|
||||
*
|
||||
* All the requests coming from the content page will be redirected to the
|
||||
* concrete class object.
|
||||
*
|
||||
* Consider navigator.mozFMRadio.enable(). Here is the call sequence:
|
||||
* - OOP
|
||||
* Child:
|
||||
* (1) Call navigator.mozFMRadio.enable().
|
||||
* (2) Return a DOMRequest object, and call FMRadioChild.Enable() with a
|
||||
* ReplyRunnable object.
|
||||
* (3) Send IPC message to main process.
|
||||
* Parent:
|
||||
* (4) Call FMRadioService::Enable() with a ReplyRunnable object.
|
||||
* (5) Call hal::EnableFMRadio().
|
||||
* (6) Notify FMRadioService object when FM radio HW is enabled.
|
||||
* (7) Dispatch the ReplyRunnable object created in (4).
|
||||
* (8) Send IPC message back to child process.
|
||||
* Child:
|
||||
* (9) Dispatch the ReplyRunnable object created in (2).
|
||||
* (10) Fire success callback of the DOMRequest Object created in (2).
|
||||
* _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
* | OOP |
|
||||
* | |
|
||||
* Page FMRadio | FMRadioChild IPC | FMRadioService Hal
|
||||
* | (1) | | | | | | |
|
||||
* |----->| (2) | | | | | |
|
||||
* | |--------|--------->| (3) | | | |
|
||||
* | | | |-----------> | | (4) | |
|
||||
* | | | | |--|---------->| (5) |
|
||||
* | | | | | | |--------->|
|
||||
* | | | | | | | (6) |
|
||||
* | | | | | | (7) |<---------|
|
||||
* | | | | (8) |<-|-----------| |
|
||||
* | | (9) | |<----------- | | | |
|
||||
* | (10) |<-------|----------| | | | |
|
||||
* |<-----| | | | | | |
|
||||
* | |
|
||||
* |_ _ _ _ _ _ _ _ _ _ _ _ _ _|
|
||||
* - non-OOP
|
||||
* In non-OOP model, we don't need to send messages between processes, so
|
||||
* the call sequences are much more simpler, it almost just follows the
|
||||
* sequences presented in OOP model: (1) (2) (5) (6) (9) and (10).
|
||||
*
|
||||
*/
|
||||
class IFMRadioService
|
||||
{
|
||||
protected:
|
||||
virtual ~IFMRadioService() { }
|
||||
|
||||
public:
|
||||
virtual bool IsEnabled() const = 0;
|
||||
virtual double GetFrequency() const = 0;
|
||||
virtual double GetFrequencyUpperBound() const = 0;
|
||||
virtual double GetFrequencyLowerBound() const = 0;
|
||||
virtual double GetChannelWidth() const = 0;
|
||||
|
||||
virtual void Enable(double aFrequency, ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void Disable(ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void SetFrequency(double aFrequency, ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void CancelSeek(ReplyRunnable* aReplyRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Register handler to receive the FM Radio events, including:
|
||||
* - StateChangedEvent
|
||||
* - FrequencyChangedEvent
|
||||
*
|
||||
* Called by FMRadio and FMRadioParent.
|
||||
*/
|
||||
virtual void AddObserver(FMRadioEventObserver* aObserver) = 0;
|
||||
virtual void RemoveObserver(FMRadioEventObserver* aObserver) = 0;
|
||||
|
||||
/**
|
||||
* Static method to return the singleton instance. If it's in the child
|
||||
* process, we will get an object of FMRadioChild.
|
||||
*/
|
||||
static IFMRadioService* Singleton();
|
||||
};
|
||||
|
||||
enum FMRadioState
|
||||
{
|
||||
Disabled,
|
||||
Disabling,
|
||||
Enabling,
|
||||
Enabled,
|
||||
Seeking
|
||||
};
|
||||
|
||||
class FMRadioService MOZ_FINAL : public IFMRadioService
|
||||
, public hal::FMRadioObserver
|
||||
, public nsIObserver
|
||||
{
|
||||
friend class ReadRilSettingTask;
|
||||
friend class SetFrequencyRunnable;
|
||||
|
||||
public:
|
||||
static FMRadioService* Singleton();
|
||||
virtual ~FMRadioService();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual bool IsEnabled() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequency() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyUpperBound() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyLowerBound() const MOZ_OVERRIDE;
|
||||
virtual double GetChannelWidth() const MOZ_OVERRIDE;
|
||||
|
||||
virtual void Enable(double aFrequency, ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Disable(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void SetFrequency(double aFrequency, ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void CancelSeek(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
|
||||
/* FMRadioObserver */
|
||||
void Notify(const hal::FMRadioOperationInformation& aInfo) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
protected:
|
||||
FMRadioService();
|
||||
|
||||
private:
|
||||
int32_t RoundFrequency(double aFrequencyInMHz);
|
||||
|
||||
void NotifyFMRadioEvent(FMRadioEventType aType);
|
||||
void DoDisable();
|
||||
void TransitionState(const FMRadioResponseType& aResponse, FMRadioState aState);
|
||||
void SetState(FMRadioState aState);
|
||||
void UpdatePowerState();
|
||||
void UpdateFrequency();
|
||||
|
||||
private:
|
||||
bool mEnabled;
|
||||
|
||||
int32_t mPendingFrequencyInKHz;
|
||||
|
||||
FMRadioState mState;
|
||||
|
||||
bool mHasReadRilSetting;
|
||||
bool mRilDisabled;
|
||||
|
||||
double mUpperBoundInKHz;
|
||||
double mLowerBoundInKHz;
|
||||
double mChannelWidthInKHz;
|
||||
|
||||
nsRefPtr<ReplyRunnable> mPendingRequest;
|
||||
|
||||
FMRadioEventObserverList mObserverList;
|
||||
|
||||
static StaticRefPtr<FMRadioService> sFMRadioService;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradioservice_h__
|
||||
|
@ -2,7 +2,7 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@ -13,3 +13,4 @@ include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
35
dom/fmradio/moz.build
Normal file
35
dom/fmradio/moz.build
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
if CONFIG['MOZ_B2G_FM']:
|
||||
DIRS += [
|
||||
'ipc',
|
||||
]
|
||||
|
||||
MODULE = 'dom'
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FMRadio.h',
|
||||
'FMRadioCommon.h',
|
||||
'FMRadioService.h',
|
||||
]
|
||||
|
||||
CPP_SOURCES += [
|
||||
'FMRadio.cpp',
|
||||
'FMRadioService.cpp',
|
||||
]
|
||||
|
||||
LIBXUL_LIBRARY = True
|
||||
|
||||
LIBRARY_NAME = 'domfmradio_s'
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'ipc/PFMRadio.ipdl',
|
||||
'ipc/PFMRadioRequest.ipdl',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -49,6 +49,7 @@ PARALLEL_DIRS += [
|
||||
'devicestorage',
|
||||
'encoding',
|
||||
'file',
|
||||
'fmradio',
|
||||
'media',
|
||||
'messages',
|
||||
'power',
|
||||
@ -86,9 +87,6 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
'voicemail',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G_FM']:
|
||||
PARALLEL_DIRS += ['fm']
|
||||
|
||||
if CONFIG['MOZ_PAY']:
|
||||
PARALLEL_DIRS += ['payment']
|
||||
|
||||
|
@ -19,8 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=815105
|
||||
var gData = [
|
||||
{
|
||||
perm: ["fmradio"],
|
||||
needParentPerm: true,
|
||||
obj: "mozFMRadio",
|
||||
idl: "nsIDOMFMRadio",
|
||||
webidl: "FMRadio",
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
102
dom/webidl/FMRadio.webidl
Normal file
102
dom/webidl/FMRadio.webidl
Normal file
@ -0,0 +1,102 @@
|
||||
/* 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/. */
|
||||
|
||||
interface FMRadio : EventTarget {
|
||||
/* Indicates if the FM radio is enabled. */
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/* Indicates if the antenna is plugged and available. */
|
||||
readonly attribute boolean antennaAvailable;
|
||||
|
||||
/**
|
||||
* Current frequency in MHz. The value will be null if the FM radio is
|
||||
* disabled.
|
||||
*/
|
||||
readonly attribute double? frequency;
|
||||
|
||||
/* The upper bound of frequency in MHz. */
|
||||
readonly attribute double frequencyUpperBound;
|
||||
|
||||
/* The lower bound of frequency in MHz. */
|
||||
readonly attribute double frequencyLowerBound;
|
||||
|
||||
/**
|
||||
* The difference in frequency between two "adjacent" channels, in MHz. That
|
||||
* is, any two radio channels' frequencies differ by at least channelWidth
|
||||
* MHz. Usually, the value is one of:
|
||||
* - 0.05 MHz
|
||||
* - 0.1 MHz
|
||||
* - 0.2 MHz
|
||||
*/
|
||||
readonly attribute double channelWidth;
|
||||
|
||||
/* Fired when the FM radio is enabled. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler onenabled;
|
||||
|
||||
/* Fired when the FM radio is disabled. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler ondisabled;
|
||||
|
||||
/**
|
||||
* Fired when the antenna becomes available or unavailable, i.e., fired when
|
||||
* the antennaAvailable attribute changes.
|
||||
*/
|
||||
[SetterThrows]
|
||||
attribute EventHandler onantennaavailablechange;
|
||||
|
||||
/* Fired when the FM radio's frequency is changed. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler onfrequencychange;
|
||||
|
||||
/**
|
||||
* Power the FM radio off. The disabled event will be fired if this request
|
||||
* completes successfully.
|
||||
*/
|
||||
DOMRequest disable();
|
||||
|
||||
/**
|
||||
* Power the FM radio on, and tune the radio to the given frequency in MHz.
|
||||
* This will fail if the given frequency is out of range. The enabled event
|
||||
* and frequencychange event will be fired if this request completes
|
||||
* successfully.
|
||||
*/
|
||||
DOMRequest enable(double frequency);
|
||||
|
||||
/**
|
||||
* Tune the FM radio to the given frequency. This will fail if the given
|
||||
* frequency is out of range.
|
||||
*
|
||||
* Note that the FM radio may not tuned to the exact frequency given. To get
|
||||
* the frequency the radio is actually tuned to, wait for the request to fire
|
||||
* sucess (or wait for the frequencychange event to fire), and then read the
|
||||
* frequency attribute.
|
||||
*/
|
||||
DOMRequest setFrequency(double frequency);
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek up to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once: If the radio is seeking when the seekUp
|
||||
* is called, error will be fired.
|
||||
*/
|
||||
DOMRequest seekUp();
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek down to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once: If the radio is seeking when the
|
||||
* seekDown is called, error will be fired.
|
||||
*/
|
||||
DOMRequest seekDown();
|
||||
|
||||
/**
|
||||
* Cancel the seek action. If the radio is not currently seeking up or down,
|
||||
* error will be fired.
|
||||
*/
|
||||
DOMRequest cancelSeek();
|
||||
};
|
||||
|
@ -297,6 +297,13 @@ partial interface Navigator {
|
||||
};
|
||||
#endif // MOZ_B2G_BT
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasFMRadioSupport"]
|
||||
readonly attribute FMRadio mozFMRadio;
|
||||
};
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
// nsIDOMMozNavigatorTime
|
||||
partial interface Navigator {
|
||||
|
@ -525,6 +525,10 @@ webidl_files += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_B2G_FM
|
||||
webidl_files += FMRadio.webidl
|
||||
endif
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
test_webidl_files := \
|
||||
TestCodeGen.webidl \
|
||||
|
@ -122,7 +122,8 @@ endif #}
|
||||
|
||||
ifdef MOZ_B2G_FM #{
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/dom/fm/$(LIB_PREFIX)domfm_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/fmradio/$(LIB_PREFIX)domfmradio_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/fmradio/ipc/$(LIB_PREFIX)domfmradio_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
endif #}
|
||||
|
||||
@ -326,7 +327,7 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/gonk
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_B2G_FM #{
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fm
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fmradio
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_B2G_BT #{
|
||||
|
@ -125,11 +125,6 @@ using mozilla::dom::gonk::AudioManager;
|
||||
using mozilla::system::nsVolumeService;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
#include "FMRadio.h"
|
||||
using mozilla::dom::fm::FMRadio;
|
||||
#endif
|
||||
|
||||
#include "AudioChannelAgent.h"
|
||||
using mozilla::dom::AudioChannelAgent;
|
||||
|
||||
@ -303,10 +298,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSynthVoiceRegistry,
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioManager)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FMRadio)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioChannelAgent)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors)
|
||||
@ -761,10 +752,6 @@ NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_VOLUMESERVICE_CID);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_DEFINE_NAMED_CID(NS_FMRADIO_CID);
|
||||
#endif
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_AUDIOCHANNELAGENT_CID);
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_HTMLEDITOR_CID);
|
||||
@ -1049,9 +1036,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
{ &kNS_AUDIOMANAGER_CID, true, NULL, AudioManagerConstructor },
|
||||
{ &kNS_VOLUMESERVICE_CID, true, NULL, nsVolumeServiceConstructor },
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
{ &kNS_FMRADIO_CID, true, NULL, FMRadioConstructor },
|
||||
#endif
|
||||
{ &kNS_AUDIOCHANNELAGENT_CID, true, NULL, AudioChannelAgentConstructor },
|
||||
{ &kNS_HTMLEDITOR_CID, false, NULL, nsHTMLEditorConstructor },
|
||||
@ -1207,9 +1191,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
{ NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },
|
||||
{ NS_VOLUMESERVICE_CONTRACTID, &kNS_VOLUMESERVICE_CID },
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
{ NS_FMRADIO_CONTRACTID, &kNS_FMRADIO_CID },
|
||||
#endif
|
||||
{ NS_AUDIOCHANNELAGENT_CONTRACTID, &kNS_AUDIOCHANNELAGENT_CID },
|
||||
{ "@mozilla.org/editor/htmleditor;1", &kNS_HTMLEDITOR_CID },
|
||||
|
Loading…
Reference in New Issue
Block a user