author | Michael Wu <mwu@mozilla.com> |
Tue, 30 Sep 2014 12:57:52 -0400 | |
changeset 208133 | ba6ad0e48fe55183ea73ad286c38363fd95c9eea |
parent 208132 | fa48349c79451fa148a61848549fab65bde6f06f |
child 208134 | 14d75b59c56c15544ebebd39855661fc8ada6fb1 |
push id | 27577 |
push user | cbook@mozilla.com |
push date | Wed, 01 Oct 2014 13:05:47 +0000 |
treeherder | autoland@835ef55e175e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ehsan, pzhang, khuey |
bugs | 864327 |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -791,51 +791,58 @@ GK_ATOM(onmozfullscreenchange, "onmozful GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror") GK_ATOM(onmozpointerlockchange, "onmozpointerlockchange") GK_ATOM(onmozpointerlockerror, "onmozpointerlockerror") GK_ATOM(onmoztimechange, "onmoztimechange") GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll") GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged") GK_ATOM(onmoznetworkupload, "onmoznetworkupload") GK_ATOM(onmoznetworkdownload, "onmoznetworkdownload") +GK_ATOM(onnewrdsgroup, "onnewrdsgroup") GK_ATOM(onnoupdate, "onnoupdate") GK_ATOM(onobsolete, "onobsolete") GK_ATOM(ononline, "ononline") GK_ATOM(onoffline, "onoffline") GK_ATOM(onopen, "onopen") GK_ATOM(onotastatuschange, "onotastatuschange") GK_ATOM(onoverflow, "onoverflow") GK_ATOM(onoverflowchanged, "onoverflowchanged") GK_ATOM(onpagehide, "onpagehide") GK_ATOM(onpageshow, "onpageshow") GK_ATOM(onpaint, "onpaint") GK_ATOM(onpairedstatuschanged, "onpairedstatuschanged") GK_ATOM(onpairingconfirmationreq, "onpairingconfirmationreq") GK_ATOM(onpairingconsentreq, "onpairingconsentreq") GK_ATOM(onpaste, "onpaste") GK_ATOM(onpendingchange, "onpendingchange") +GK_ATOM(onpichange, "onpichange") GK_ATOM(onpopuphidden, "onpopuphidden") GK_ATOM(onpopuphiding, "onpopuphiding") GK_ATOM(onpopupshowing, "onpopupshowing") GK_ATOM(onpopupshown, "onpopupshown") +GK_ATOM(onpschange, "onpschange") +GK_ATOM(onptychange, "onptychange") GK_ATOM(onradiostatechange, "onradiostatechange") +GK_ATOM(onrdsdisabled, "onrdsdisabled") +GK_ATOM(onrdsenabled, "onrdsenabled") GK_ATOM(onreaderror, "onreaderror") GK_ATOM(onreadsuccess, "onreadsuccess") GK_ATOM(onready, "onready") GK_ATOM(onreadystatechange, "onreadystatechange") GK_ATOM(onreceived, "onreceived") GK_ATOM(onremoteheld, "onremoteheld") GK_ATOM(onremoteresumed, "onremoteresumed") GK_ATOM(onresourcetimingbufferfull, "onresourcetimingbufferfull") GK_ATOM(onretrieving, "onretrieving") GK_ATOM(onRequest, "onRequest") GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus") GK_ATOM(onreset, "onreset") GK_ATOM(onresuming, "onresuming") GK_ATOM(onresize, "onresize") +GK_ATOM(onrtchange, "onrtchange") GK_ATOM(onscostatuschanged, "onscostatuschanged") GK_ATOM(onscroll, "onscroll") GK_ATOM(onselect, "onselect") GK_ATOM(onsending, "onsending") GK_ATOM(onsent, "onsent") GK_ATOM(onset, "onset") GK_ATOM(onshow, "onshow") GK_ATOM(onstatechange, "onstatechange")
--- a/dom/fmradio/FMRadio.cpp +++ b/dom/fmradio/FMRadio.cpp @@ -8,16 +8,17 @@ #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 "mozilla/dom/TypedArray.h" #include "DOMRequest.h" #include "nsDOMClassInfo.h" #include "nsIDocShell.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIAudioManager.h" #undef LOG #define LOG(args...) FM_LOG("FMRadio", args) @@ -100,16 +101,17 @@ private: FMRadioRequestArgs::Type mType; nsWeakPtr mFMRadio; }; NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest) FMRadio::FMRadio() : mHeadphoneState(SWITCH_STATE_OFF) + , mRdsGroupMask(0) , mAudioChannelAgentEnabled(false) , mHasInternalAntenna(false) , mIsShutdown(false) { LOG("FMRadio is initialized."); SetIsDOMBinding(); } @@ -215,29 +217,57 @@ FMRadio::Notify(const FMRadioEventType& if (mAudioChannelAgentEnabled) { mAudioChannelAgent->StopPlaying(); mAudioChannelAgentEnabled = false; } DispatchTrustedEvent(NS_LITERAL_STRING("disabled")); } break; + case RDSEnabledChanged: + if (RdsEnabled()) { + DispatchTrustedEvent(NS_LITERAL_STRING("rdsenabled")); + } else { + DispatchTrustedEvent(NS_LITERAL_STRING("rdsdisabled")); + } + break; + case PIChanged: + DispatchTrustedEvent(NS_LITERAL_STRING("pichange")); + break; + case PSChanged: + DispatchTrustedEvent(NS_LITERAL_STRING("pschange")); + break; + case RadiotextChanged: + DispatchTrustedEvent(NS_LITERAL_STRING("rtchange")); + break; + case PTYChanged: + DispatchTrustedEvent(NS_LITERAL_STRING("ptychange")); + break; + case NewRDSGroup: + DispatchTrustedEvent(NS_LITERAL_STRING("newrdsgroup")); + break; default: MOZ_CRASH(); } } /* static */ bool FMRadio::Enabled() { return IFMRadioService::Singleton()->IsEnabled(); } bool +FMRadio::RdsEnabled() +{ + return IFMRadioService::Singleton()->IsRDSEnabled(); +} + +bool FMRadio::AntennaAvailable() const { return mHasInternalAntenna ? true : (mHeadphoneState != SWITCH_STATE_OFF) && (mHeadphoneState != SWITCH_STATE_UNKNOWN); } Nullable<double> FMRadio::GetFrequency() const @@ -260,16 +290,79 @@ FMRadio::FrequencyLowerBound() const } double FMRadio::ChannelWidth() const { return IFMRadioService::Singleton()->GetChannelWidth(); } +uint32_t +FMRadio::RdsGroupMask() const +{ + return mRdsGroupMask; +} + +void +FMRadio::SetRdsGroupMask(uint32_t aRdsGroupMask) +{ + mRdsGroupMask = aRdsGroupMask; + IFMRadioService::Singleton()->SetRDSGroupMask(aRdsGroupMask); +} + +Nullable<unsigned short> +FMRadio::GetPi() const +{ + return IFMRadioService::Singleton()->GetPi(); +} + +Nullable<uint8_t> +FMRadio::GetPty() const +{ + return IFMRadioService::Singleton()->GetPty(); +} + +void +FMRadio::GetPs(DOMString& aPsname) const +{ + if (!IFMRadioService::Singleton()->GetPs(aPsname)) { + aPsname.SetNull(); + } +} + +void +FMRadio::GetRt(DOMString& aRadiotext) const +{ + if (!IFMRadioService::Singleton()->GetRt(aRadiotext)) { + aRadiotext.SetNull(); + } +} + +void +FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval) +{ + uint64_t group; + if (!IFMRadioService::Singleton()->GetRdsgroup(group)) { + return; + } + + JSObject *rdsgroup = Uint16Array::Create(cx, this, 4); + uint16_t *data = JS_GetUint16ArrayData(rdsgroup); + data[3] = group & 0xFFFF; + group >>= 16; + data[2] = group & 0xFFFF; + group >>= 16; + data[1] = group & 0xFFFF; + group >>= 16; + data[0] = group & 0xFFFF; + + JS::ExposeObjectToActiveJS(rdsgroup); + retval.set(rdsgroup); +} + already_AddRefed<DOMRequest> FMRadio::Enable(double aFrequency) { nsCOMPtr<nsPIDOMWindow> win = GetOwner(); if (!win) { return nullptr; } @@ -345,16 +438,42 @@ FMRadio::CancelSeek() } nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this); IFMRadioService::Singleton()->CancelSeek(r); return r.forget(); } +already_AddRefed<DOMRequest> +FMRadio::EnableRDS() +{ + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); + if (!win) { + return nullptr; + } + + nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this); + IFMRadioService::Singleton()->EnableRDS(r); + return r.forget(); +} + +already_AddRefed<DOMRequest> +FMRadio::DisableRDS() +{ + nsCOMPtr<nsPIDOMWindow> win = GetOwner(); + if (!win) { + return nullptr; + } + + nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this); + FMRadioService::Singleton()->DisableRDS(r); + return r.forget(); +} + NS_IMETHODIMP FMRadio::HandleEvent(nsIDOMEvent* aEvent) { nsAutoString type; aEvent->GetType(type); if (!type.EqualsLiteral("visibilitychange")) { return NS_ERROR_FAILURE;
--- a/dom/fmradio/FMRadio.h +++ b/dom/fmradio/FMRadio.h @@ -50,53 +50,81 @@ public: { return GetOwner(); } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; static bool Enabled(); + bool RdsEnabled(); + bool AntennaAvailable() const; Nullable<double> GetFrequency() const; double FrequencyUpperBound() const; double FrequencyLowerBound() const; double ChannelWidth() const; + uint32_t RdsGroupMask() const; + + void SetRdsGroupMask(uint32_t aRdsGroupMask); + + Nullable<unsigned short> GetPi() const; + + Nullable<uint8_t> GetPty() const; + + void GetPs(DOMString& aPsname) const; + + void GetRt(DOMString& aRadiotext) const; + + void GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval); + 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(); + already_AddRefed<DOMRequest> EnableRDS(); + + already_AddRefed<DOMRequest> DisableRDS(); + IMPL_EVENT_HANDLER(enabled); IMPL_EVENT_HANDLER(disabled); + IMPL_EVENT_HANDLER(rdsenabled); + IMPL_EVENT_HANDLER(rdsdisabled); IMPL_EVENT_HANDLER(antennaavailablechange); IMPL_EVENT_HANDLER(frequencychange); + IMPL_EVENT_HANDLER(pichange); + IMPL_EVENT_HANDLER(ptychange); + IMPL_EVENT_HANDLER(pschange); + IMPL_EVENT_HANDLER(rtchange); + IMPL_EVENT_HANDLER(newrdsgroup); // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); private: ~FMRadio(); void SetCanPlay(bool aCanPlay); void EnableAudioChannelAgent(); hal::SwitchState mHeadphoneState; + uint32_t mRdsGroupMask; bool mAudioChannelAgentEnabled; bool mHasInternalAntenna; bool mIsShutdown; nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent; }; END_FMRADIO_NAMESPACE
--- a/dom/fmradio/FMRadioCommon.h +++ b/dom/fmradio/FMRadioCommon.h @@ -25,17 +25,23 @@ #define END_FMRADIO_NAMESPACE \ } /* namespace dom */ } /* namespace mozilla */ BEGIN_FMRADIO_NAMESPACE enum FMRadioEventType { FrequencyChanged, - EnabledChanged + EnabledChanged, + RDSEnabledChanged, + PIChanged, + PSChanged, + PTYChanged, + RadiotextChanged, + NewRDSGroup }; typedef mozilla::Observer<FMRadioEventType> FMRadioEventObserver; typedef mozilla::ObserverList<FMRadioEventType> FMRadioEventObserverList; END_FMRADIO_NAMESPACE #endif /* FMRADIOCOMMON_H_ */
--- a/dom/fmradio/FMRadioService.cpp +++ b/dom/fmradio/FMRadioService.cpp @@ -21,16 +21,18 @@ #define BAND_87500_108000_kHz 1 #define BAND_76000_108000_kHz 2 #define BAND_76000_90000_kHz 3 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed" #define SETTING_KEY_AIRPLANEMODE_ENABLED "airplaneMode.enabled" +#define DOM_PARSED_RDS_GROUPS ((0x2 << 30) | (0x3 << 4) | (0x3 << 0)) + using namespace mozilla::hal; using mozilla::Preferences; BEGIN_FMRADIO_NAMESPACE // static IFMRadioService* IFMRadioService::Singleton() @@ -44,19 +46,36 @@ IFMRadioService::Singleton() StaticRefPtr<FMRadioService> FMRadioService::sFMRadioService; FMRadioService::FMRadioService() : mPendingFrequencyInKHz(0) , mState(Disabled) , mHasReadAirplaneModeSetting(false) , mAirplaneModeEnabled(false) + , mRDSEnabled(false) , mPendingRequest(nullptr) , mObserverList(FMRadioEventObserverList()) + , mRDSGroupMask(0) + , mLastPI(0) + , mPI(0) + , mPTY(0) + , mPISet(false) + , mPTYSet(false) + , mRDSLock("FMRadioService::mRDSLock") + , mPSNameState(0) + , mRadiotextAB(false) + , mRDSGroupSet(false) + , mPSNameSet(false) + , mRadiotextSet(false) { + memset(mPSName, 0, sizeof(mPSName)); + memset(mRadiotext, 0, sizeof(mRadiotext)); + memset(mTempPSName, 0, sizeof(mTempPSName)); + memset(mTempRadiotext, 0, sizeof(mTempRadiotext)); // Read power state and frequency from Hal. mEnabled = IsFMRadioOn(); if (mEnabled) { mPendingFrequencyInKHz = GetFMRadioFrequency(); SetState(Enabled); } @@ -105,20 +124,22 @@ FMRadioService::FMRadioService() if (obs && NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, /* useWeak */ false))) { NS_WARNING("Failed to add settings change observer!"); } RegisterFMRadioObserver(this); + RegisterFMRadioRDSObserver(this); } FMRadioService::~FMRadioService() { + UnregisterFMRadioRDSObserver(this); UnregisterFMRadioObserver(this); } class EnableRunnable MOZ_FINAL : public nsRunnable { public: EnableRunnable(uint32_t aUpperLimit, uint32_t aLowerLimit, uint32_t aSpaceType, uint32_t aPreemphasis) : mUpperLimit(aUpperLimit) @@ -272,16 +293,31 @@ public: return NS_OK; } private: FMRadioSeekDirection mDirection; }; +class NotifyRunnable MOZ_FINAL : public nsRunnable +{ +public: + NotifyRunnable(FMRadioEventType aType) : mType(aType) { } + + NS_IMETHOD Run() + { + FMRadioService::Singleton()->NotifyFMRadioEvent(mType); + return NS_OK; + } + +private: + FMRadioEventType mType; +}; + void FMRadioService::TransitionState(const FMRadioResponseType& aResponse, FMRadioState aState) { if (mPendingRequest) { mPendingRequest->SetReply(aResponse); NS_DispatchToMainThread(mPendingRequest); } @@ -369,16 +405,23 @@ FMRadioService::RoundFrequency(double aF bool FMRadioService::IsEnabled() const { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); return IsFMRadioOn(); } +bool +FMRadioService::IsRDSEnabled() const +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + return mRDSEnabled; +} + double FMRadioService::GetFrequency() const { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); if (IsEnabled()) { int32_t frequencyInKHz = GetFMRadioFrequency(); return frequencyInKHz / 1000.0; } @@ -402,16 +445,64 @@ FMRadioService::GetFrequencyLowerBound() double FMRadioService::GetChannelWidth() const { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); return mChannelWidthInKHz / 1000.0; } +Nullable<unsigned short> +FMRadioService::GetPi() const +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + if (!mPISet) { + return Nullable<unsigned short>(); + } + return Nullable<unsigned short>(mPI); +} + +Nullable<uint8_t> +FMRadioService::GetPty() const +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + if (!mPTYSet) { + return Nullable<uint8_t>(); + } + return Nullable<uint8_t>(mPTY); +} + +bool +FMRadioService::GetPs(nsString& aPSName) +{ + MutexAutoLock lock(mRDSLock); + if (mPSNameSet) { + aPSName = nsString(mPSName); + } + return mPSNameSet; +} + +bool +FMRadioService::GetRt(nsString& aRadiotext) +{ + MutexAutoLock lock(mRDSLock); + if (mRadiotextSet) { + aRadiotext = nsString(mRadiotext); + } + return mRadiotextSet; +} + +bool +FMRadioService::GetRdsgroup(uint64_t& aRDSGroup) +{ + MutexAutoLock lock(mRDSLock); + aRDSGroup = mRDSGroup; + return mRDSGroupSet; +} + void FMRadioService::Enable(double aFrequencyInMHz, FMRadioReplyRunnable* aReplyRunnable) { MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); MOZ_ASSERT(aReplyRunnable); switch (mState) { @@ -674,16 +765,57 @@ FMRadioService::CancelSeek(FMRadioReplyR TransitionState( ErrorResponse(NS_LITERAL_STRING("Seek action is cancelled")), Enabled); aReplyRunnable->SetReply(SuccessResponse()); NS_DispatchToMainThread(aReplyRunnable); } +void +FMRadioService::SetRDSGroupMask(uint32_t aRDSGroupMask) +{ + mRDSGroupMask = aRDSGroupMask; + if (IsFMRadioOn()) { + hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS); + } +} + +void +FMRadioService::EnableRDS(FMRadioReplyRunnable* aReplyRunnable) +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(aReplyRunnable); + + mRDSEnabled = true; + if (IsFMRadioOn()) { + hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS); + } + + aReplyRunnable->SetReply(SuccessResponse()); + NS_DispatchToMainThread(aReplyRunnable); + NS_DispatchToMainThread(new NotifyRunnable(RDSEnabledChanged)); +} + +void +FMRadioService::DisableRDS(FMRadioReplyRunnable* aReplyRunnable) +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(aReplyRunnable); + + mRDSEnabled = false; + if (IsFMRadioOn()) { + hal::DisableRDS(); + } + + aReplyRunnable->SetReply(SuccessResponse()); + NS_DispatchToMainThread(aReplyRunnable); + NS_DispatchToMainThread(new NotifyRunnable(RDSEnabledChanged)); +} + NS_IMETHODIMP FMRadioService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(sFMRadioService); @@ -755,20 +887,28 @@ FMRadioService::Notify(const FMRadioOper // 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); + + if (mRDSEnabled) { + hal::EnableRDS(mRDSGroupMask | DOM_PARSED_RDS_GROUPS); + } break; case FM_RADIO_OPERATION_DISABLE: MOZ_ASSERT(mState == Disabling); + mPISet = false; + mPTYSet = false; + memset(mPSName, 0, sizeof(mPSName)); + memset(mRadiotext, 0, sizeof(mRadiotext)); 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) { @@ -780,16 +920,284 @@ FMRadioService::Notify(const FMRadioOper case FM_RADIO_OPERATION_TUNE: UpdateFrequency(); break; default: MOZ_CRASH(); } } +/* This is defined by the RDS standard */ +static const uint16_t sRDSToUnicodeMap[256] = { + // The lower half differs from ASCII in 0x1F, 0x24, 0x5E, 0x7E + // Most control characters are replaced with 0x20 (space) + // 0x0- + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0009, 0x000A, 0x000B, 0x0020, 0x00D0, 0x0020, 0x0020, + + // 0x1- + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x001B, 0x0020, 0x0020, 0x0020, 0x00AD, + + // 0x2- + 0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + + // 0x3- + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + + // 0x4- + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + + // 0x5- + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x2015, 0x005F, + + // 0x6- + 0x2551, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + + // 0x7- + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x00AF, 0x007F, + + // 0x8- + 0x00E1, 0x00E0, 0x00E9, 0x00E8, 0x00ED, 0x00EC, 0x00F3, 0x00F2, + 0x00FA, 0x00F9, 0x00D1, 0x00C7, 0x015E, 0x00DF, 0x00A1, 0x0132, + + // 0x9- + 0x00E2, 0x00E4, 0x00EA, 0x00EB, 0x00EE, 0x00EF, 0x00F4, 0x00F6, + 0x00FB, 0x00FC, 0x00F1, 0x00E7, 0x015F, 0x011F, 0x0131, 0x0133, + + // 0xA- + 0x00AA, 0x03B1, 0x00A9, 0x2030, 0x011E, 0x011B, 0x0148, 0x0151, + 0x03C0, 0x20AC, 0x00A3, 0x0024, 0x2190, 0x2191, 0x2192, 0x2193, + + // 0xB- + 0x00BA, 0x00B9, 0x00B2, 0x00B3, 0x00B1, 0x0130, 0x0144, 0x0171, + 0x03BC, 0x00BF, 0x00F7, 0x00B0, 0x00BC, 0x00BD, 0x00BE, 0x00A7, + + // 0xC- + 0x00C1, 0x00C0, 0x00C9, 0x00C8, 0x00CD, 0x00CC, 0x00D3, 0x00D2, + 0x00DA, 0x00D9, 0x0158, 0x010C, 0x0160, 0x017D, 0x00D0, 0x013F, + + // 0xD- + 0x00C2, 0x00C4, 0x00CA, 0x00CB, 0x00CE, 0x00CF, 0x00D4, 0x00D6, + 0x00DB, 0x00DC, 0x0159, 0x010D, 0x0161, 0x017E, 0x0111, 0x0140, + + // 0xE- + 0x00C3, 0x00C5, 0x00C6, 0x0152, 0x0177, 0x00DD, 0x00D5, 0x00D8, + 0x00DE, 0x014A, 0x0154, 0x0106, 0x015A, 0x0179, 0x0166, 0x00F0, + + // 0xF- + 0x00E3, 0x00E5, 0x00E6, 0x0153, 0x0175, 0x00FD, 0x00F5, 0x00F8, + 0x00FE, 0x014B, 0x0155, 0x0107, 0x015B, 0x017A, 0x0167, 0x0020, +}; + +void +FMRadioService::Notify(const FMRadioRDSGroup& aRDSGroup) +{ + uint16_t blocks[4]; + blocks[0] = aRDSGroup.blockA(); + blocks[1] = aRDSGroup.blockB(); + blocks[2] = aRDSGroup.blockC(); + blocks[3] = aRDSGroup.blockD(); + + /* Bit 11 in block B determines whether this is a type B group. */ + uint16_t lastPI = blocks[1] & (1 << 11) ? blocks[2] : mLastPI; + + /* Update PI if it's not set or if we get two PI with the new value. */ + if ((mPI != blocks[0] && lastPI == blocks[0]) || !mPISet) { + mPI = blocks[0]; + if (!mPISet) { + mPSNameState = 0; + mRadiotextState = 0; + memset(mTempPSName, 0, sizeof(mTempPSName)); + memset(mTempRadiotext, 0, sizeof(mTempRadiotext)); + } + mPISet = true; + NS_DispatchToMainThread(new NotifyRunnable(PIChanged)); + } + mLastPI = blocks[0]; + + /* PTY is also updated using the same logic as PI */ + uint16_t pty = (blocks[1] >> 5) & 0x1F; + if ((mPTY != pty && pty == mLastPTY) || !mPTYSet) { + mPTY = pty; + mPTYSet = true; + NS_DispatchToMainThread(new NotifyRunnable(PTYChanged)); + } + mLastPTY = pty; + + uint16_t grouptype = blocks[1] >> 11; + switch (grouptype) { + case 0: // 0a + case 1: // 0b + { + uint16_t segmentAddr = (blocks[1] & 0x3); + // mPSNameState is a bitmask that lets us ensure all segments + // are received before updating the PS name. + if (!segmentAddr) { + mPSNameState = 1; + } else { + mPSNameState |= 1 << segmentAddr; + } + + uint16_t offset = segmentAddr << 1; + mTempPSName[offset] = sRDSToUnicodeMap[blocks[3] >> 8]; + mTempPSName[offset + 1] = sRDSToUnicodeMap[blocks[3] & 0xFF]; + + if (mPSNameState != 0xF) { + break; + } + + mPSNameState = 0; + if (memcmp(mTempPSName, mPSName, sizeof(mTempPSName))) { + MutexAutoLock lock(mRDSLock); + mPSNameSet = true; + memcpy(mPSName, mTempPSName, sizeof(mTempPSName)); + NS_DispatchToMainThread(new NotifyRunnable(PSChanged)); + } + break; + } + case 4: // 2a Radiotext + { + uint16_t segmentAddr = (blocks[1] & 0xF); + bool textAB = blocks[1] & (1 << 5); + if (textAB != mRadiotextAB) { + mRadiotextState = 0; + memset(mTempRadiotext, 0, sizeof(mTempRadiotext)); + mRadiotextAB = textAB; + MutexAutoLock lock(mRDSLock); + memset(mRadiotext, 0, sizeof(mRadiotext)); + NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged)); + } + + // mRadiotextState is a bitmask that lets us ensure all segments + // are received before updating the radiotext. + if (!segmentAddr) { + mRadiotextState = 1; + } else { + mRadiotextState |= 1 << segmentAddr; + } + + uint8_t segment[4]; + segment[0] = blocks[2] >> 8; + segment[1] = blocks[2] & 0xFF; + segment[2] = blocks[3] >> 8; + segment[3] = blocks[3] & 0xFF; + + uint16_t offset = segmentAddr << 2; + bool done = false; + for (int i = 0; i < 4; i++) { + if (segment[i] == '\r') { + mTempRadiotext[offset++] = 0; + done = true; + } else { + mTempRadiotext[offset++] = sRDSToUnicodeMap[segment[i]]; + } + } + if (offset == 64) { + done = true; + } + + if (!done || + (mRadiotextState + 1) != (1 << ((blocks[1] & 0xF) + 1)) || + !memcmp(mTempRadiotext, mRadiotext, sizeof(mTempRadiotext))) { + break; + } + + MutexAutoLock lock(mRDSLock); + mRadiotextSet = true; + memcpy(mRadiotext, mTempRadiotext, sizeof(mTempRadiotext)); + NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged)); + break; + } + case 5: // 2b Radiotext + { + uint16_t segmentAddr = (blocks[1] & 0xF); + bool textAB = blocks[1] & (1 << 5); + if (textAB != mRadiotextAB) { + mRadiotextState = 0; + memset(mTempRadiotext, 0, sizeof(mTempRadiotext)); + mRadiotextAB = textAB; + MutexAutoLock lock(mRDSLock); + memset(mRadiotext, 0, sizeof(mRadiotext)); + NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged)); + } + + if (!segmentAddr) { + mRadiotextState = 1; + } else { + mRadiotextState |= 1 << segmentAddr; + } + uint8_t segment[2]; + segment[0] = blocks[3] >> 8; + segment[1] = blocks[3] & 0xFF; + + uint16_t offset = segmentAddr << 1; + bool done = false; + for (int i = 0; i < 2; i++) { + if (segment[i] == '\r') { + mTempRadiotext[offset++] = 0; + done = true; + } else { + mTempRadiotext[offset++] = sRDSToUnicodeMap[segment[i]]; + } + } + if (offset == 32) { + done = true; + } + + if (!done || + (mRadiotextState + 1) != (1 << ((blocks[1] & 0xF) + 1)) || + !memcmp(mTempRadiotext, mRadiotext, sizeof(mTempRadiotext))) { + break; + } + + MutexAutoLock lock(mRDSLock); + mRadiotextSet = true; + memcpy(mRadiotext, mTempRadiotext, sizeof(mTempRadiotext)); + NS_DispatchToMainThread(new NotifyRunnable(RadiotextChanged)); + break; + } + case 31: // 15b Fast Tuning and Switching + { + uint16_t secondPty = (blocks[3] >> 5) & 0x1F; + if (pty == mPTY || pty != secondPty) { + break; + } + mPTY = pty; + NS_DispatchToMainThread(new NotifyRunnable(PTYChanged)); + break; + } + } + + // Only notify users of raw RDS groups that they're interested in. + // We always receive DOM_PARSED_RDS_GROUPS when RDS is enabled. + if (!(mRDSGroupMask & (1 << grouptype))) { + return; + } + + uint64_t newgroup = blocks[0]; + newgroup <<= 16; + newgroup |= blocks[1]; + newgroup <<= 16; + newgroup |= blocks[2]; + newgroup <<= 16; + newgroup |= blocks[3]; + + MutexAutoLock lock(mRDSLock); + mRDSGroup = newgroup; + mRDSGroupSet = true; + NS_DispatchToMainThread(new NotifyRunnable(NewRDSGroup)); +} + void FMRadioService::UpdatePowerState() { bool enabled = IsFMRadioOn(); if (enabled != mEnabled) { mEnabled = enabled; NotifyFMRadioEvent(EnabledChanged); } @@ -797,16 +1205,23 @@ FMRadioService::UpdatePowerState() void FMRadioService::UpdateFrequency() { int32_t frequency = GetFMRadioFrequency(); if (mPendingFrequencyInKHz != frequency) { mPendingFrequencyInKHz = frequency; NotifyFMRadioEvent(FrequencyChanged); + mPISet = false; + mPTYSet = false; + memset(mPSName, 0, sizeof(mPSName)); + memset(mRadiotext, 0, sizeof(mRadiotext)); + mRDSGroupSet = false; + mPSNameSet = false; + mRadiotextSet = false; } } // static FMRadioService* FMRadioService::Singleton() { MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
--- a/dom/fmradio/FMRadioService.h +++ b/dom/fmradio/FMRadioService.h @@ -2,19 +2,21 @@ /* 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/Nullable.h" #include "mozilla/dom/PFMRadioRequest.h" #include "FMRadioCommon.h" #include "mozilla/Hal.h" +#include "mozilla/Mutex.h" #include "mozilla/StaticPtr.h" #include "mozilla/Services.h" #include "nsThreadUtils.h" #include "nsIObserver.h" #include "nsXULAppAPI.h" BEGIN_FMRADIO_NAMESPACE @@ -90,27 +92,36 @@ protected: */ class IFMRadioService { protected: virtual ~IFMRadioService() { } public: virtual bool IsEnabled() const = 0; + virtual bool IsRDSEnabled() const = 0; virtual double GetFrequency() const = 0; virtual double GetFrequencyUpperBound() const = 0; virtual double GetFrequencyLowerBound() const = 0; virtual double GetChannelWidth() const = 0; + virtual Nullable<unsigned short> GetPi() const = 0; + virtual Nullable<uint8_t> GetPty() const = 0; + virtual bool GetPs(nsString& aPsname) = 0; + virtual bool GetRt(nsString& aRadiotext) = 0; + virtual bool GetRdsgroup(uint64_t& aRDSGroup) = 0; virtual void Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) = 0; virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) = 0; virtual void SetFrequency(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) = 0; virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection, FMRadioReplyRunnable* aReplyRunnable) = 0; virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) = 0; + virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) = 0; + virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) = 0; + virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) = 0; /** * Register handler to receive the FM Radio events, including: * - StateChangedEvent * - FrequencyChangedEvent * * Called by FMRadio and FMRadioParent. */ @@ -133,50 +144,63 @@ enum FMRadioState Disabling, Enabling, Enabled, Seeking }; class FMRadioService MOZ_FINAL : public IFMRadioService , public hal::FMRadioObserver + , public hal::FMRadioRDSObserver , public nsIObserver { friend class ReadAirplaneModeSettingTask; friend class EnableRunnable; friend class DisableRunnable; + friend class NotifyRunnable; public: static FMRadioService* Singleton(); virtual ~FMRadioService(); NS_DECL_ISUPPORTS virtual bool IsEnabled() const MOZ_OVERRIDE; + virtual bool IsRDSEnabled() 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 Nullable<unsigned short> GetPi() const MOZ_OVERRIDE; + virtual Nullable<uint8_t> GetPty() const MOZ_OVERRIDE; + virtual bool GetPs(nsString& aPsname) MOZ_OVERRIDE; + virtual bool GetRt(nsString& aRadiotext) MOZ_OVERRIDE; + virtual bool GetRdsgroup(uint64_t& aRDSGroup) MOZ_OVERRIDE; virtual void Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void SetFrequency(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; + virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) MOZ_OVERRIDE; + virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; + virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE; virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE; virtual void EnableAudio(bool aAudioEnabled) MOZ_OVERRIDE; /* FMRadioObserver */ void Notify(const hal::FMRadioOperationInformation& aInfo) MOZ_OVERRIDE; + /* FMRadioRDSObserver */ + void Notify(const hal::FMRadioRDSGroup& aRDSGroup) MOZ_OVERRIDE; NS_DECL_NSIOBSERVER protected: FMRadioService(); private: int32_t RoundFrequency(double aFrequencyInMHz); @@ -192,26 +216,51 @@ private: bool mEnabled; int32_t mPendingFrequencyInKHz; FMRadioState mState; bool mHasReadAirplaneModeSetting; bool mAirplaneModeEnabled; + bool mRDSEnabled; uint32_t mUpperBoundInKHz; uint32_t mLowerBoundInKHz; uint32_t mChannelWidthInKHz; uint32_t mPreemphasis; nsCOMPtr<nsIThread> mTuneThread; nsRefPtr<FMRadioReplyRunnable> mPendingRequest; FMRadioEventObserverList mObserverList; static StaticRefPtr<FMRadioService> sFMRadioService; + + uint32_t mRDSGroupMask; + + uint16_t mLastPI; + uint16_t mLastPTY; + Atomic<uint32_t> mPI; + Atomic<uint32_t> mPTY; + Atomic<bool> mPISet; + Atomic<bool> mPTYSet; + + /* Protects mPSName, mRadiotext, and mRDSGroup */ + Mutex mRDSLock; + char16_t mPSName[9]; + char16_t mRadiotext[65]; + uint64_t mRDSGroup; + + uint8_t mPSNameState; + uint16_t mRadiotextState; + uint16_t mTempPSName[8]; + uint16_t mTempRadiotext[64]; + bool mRadiotextAB; + bool mRDSGroupSet; + bool mPSNameSet; + bool mRadiotextSet; }; END_FMRADIO_NAMESPACE #endif // mozilla_dom_fmradioservice_h__
--- a/dom/fmradio/ipc/FMRadioChild.cpp +++ b/dom/fmradio/ipc/FMRadioChild.cpp @@ -11,17 +11,23 @@ using namespace mozilla::hal; BEGIN_FMRADIO_NAMESPACE StaticAutoPtr<FMRadioChild> FMRadioChild::sFMRadioChild; FMRadioChild::FMRadioChild() : mEnabled(false) + , mRDSEnabled(false) + , mRDSGroupSet(false) + , mPSNameSet(false) + , mRadiotextSet(false) , mFrequency(0) + , mRDSGroup(0) + , mRDSGroupMask(0) , mObserverList(FMRadioEventObserverList()) { MOZ_COUNT_CTOR(FMRadioChild); ContentChild::GetSingleton()->SendPFMRadioConstructor(this); StatusInfo statusInfo; SendGetStatusInfo(&statusInfo); @@ -39,16 +45,22 @@ FMRadioChild::~FMRadioChild() } bool FMRadioChild::IsEnabled() const { return mEnabled; } +bool +FMRadioChild::IsRDSEnabled() const +{ + return mRDSEnabled; +} + double FMRadioChild::GetFrequency() const { return mFrequency; } double @@ -64,16 +76,53 @@ FMRadioChild::GetFrequencyLowerBound() c } double FMRadioChild::GetChannelWidth() const { return mChannelWidth; } +Nullable<unsigned short> +FMRadioChild::GetPi() const +{ + return mPI; +} + +Nullable<uint8_t> +FMRadioChild::GetPty() const +{ + return mPTY; +} + +bool +FMRadioChild::GetPs(nsString& aPSName) +{ + if (mPSNameSet) { + aPSName = mPSName; + } + return mPSNameSet; +} + +bool +FMRadioChild::GetRt(nsString& aRadiotext) +{ + if (mRadiotextSet) { + aRadiotext = mRadiotext; + } + return mRadiotextSet; +} + +bool +FMRadioChild::GetRdsgroup(uint64_t& aRDSGroup) +{ + aRDSGroup = mRDSGroup; + return mRDSGroupSet; +} + void FMRadioChild::Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) { SendRequest(aReplyRunnable, EnableRequestArgs(aFrequency)); } void FMRadioChild::Disable(FMRadioReplyRunnable* aReplyRunnable) @@ -96,16 +145,35 @@ FMRadioChild::Seek(FMRadioSeekDirection } void FMRadioChild::CancelSeek(FMRadioReplyRunnable* aReplyRunnable) { SendRequest(aReplyRunnable, CancelSeekRequestArgs()); } +void +FMRadioChild::SetRDSGroupMask(uint32_t aRDSGroupMask) +{ + mRDSGroupMask = aRDSGroupMask; + SendSetRDSGroupMask(aRDSGroupMask); +} + +void +FMRadioChild::EnableRDS(FMRadioReplyRunnable* aReplyRunnable) +{ + SendRequest(aReplyRunnable, EnableRDSArgs()); +} + +void +FMRadioChild::DisableRDS(FMRadioReplyRunnable* aReplyRunnable) +{ + SendRequest(aReplyRunnable, DisableRDSArgs()); +} + inline void FMRadioChild::NotifyFMRadioEvent(FMRadioEventType aType) { mObserverList.Broadcast(aType); } void FMRadioChild::AddObserver(FMRadioEventObserver* aObserver) @@ -127,30 +195,125 @@ FMRadioChild::SendRequest(FMRadioReplyRu SendPFMRadioRequestConstructor(childRequest, aArgs); } bool FMRadioChild::RecvNotifyFrequencyChanged(const double& aFrequency) { mFrequency = aFrequency; NotifyFMRadioEvent(FrequencyChanged); + + if (!mPI.IsNull()) { + mPI.SetNull(); + NotifyFMRadioEvent(PIChanged); + } + if (!mPTY.IsNull()) { + mPTY.SetNull(); + NotifyFMRadioEvent(PTYChanged); + } + if (mPSNameSet) { + mPSNameSet = false; + mPSName.Truncate(); + NotifyFMRadioEvent(PSChanged); + } + if (mRadiotextSet) { + mRadiotextSet = false; + mRadiotext.Truncate(); + NotifyFMRadioEvent(RadiotextChanged); + } + mRDSGroupSet = false; return true; } bool FMRadioChild::RecvNotifyEnabledChanged(const bool& aEnabled, const double& aFrequency) { mEnabled = aEnabled; mFrequency = aFrequency; + if (!mEnabled) { + mPI.SetNull(); + mPTY.SetNull(); + mPSName.Truncate(); + mRadiotext.Truncate(); + mRDSGroupSet = false; + mPSNameSet = false; + mRadiotextSet = false; + } NotifyFMRadioEvent(EnabledChanged); return true; } bool +FMRadioChild::RecvNotifyRDSEnabledChanged(const bool& aEnabled) +{ + mRDSEnabled = aEnabled; + NotifyFMRadioEvent(RDSEnabledChanged); + return true; +} + +bool +FMRadioChild::RecvNotifyPIChanged(const bool& aValid, + const uint16_t& aCode) +{ + if (aValid) { + mPI.SetValue(aCode); + } else { + mPI.SetNull(); + } + NotifyFMRadioEvent(PIChanged); + return true; +} + +bool +FMRadioChild::RecvNotifyPTYChanged(const bool& aValid, + const uint8_t& aPTY) +{ + if (aValid) { + mPTY.SetValue(aPTY); + } else { + mPTY.SetNull(); + } + NotifyFMRadioEvent(PTYChanged); + return true; +} + +bool +FMRadioChild::RecvNotifyPSChanged(const nsString& aPSName) +{ + mPSNameSet = true; + mPSName = aPSName; + NotifyFMRadioEvent(PSChanged); + return true; +} + +bool +FMRadioChild::RecvNotifyRadiotextChanged(const nsString& aRadiotext) +{ + mRadiotextSet = true; + mRadiotext = aRadiotext; + NotifyFMRadioEvent(RadiotextChanged); + return true; +} + +bool +FMRadioChild::RecvNotifyNewRDSGroup(const uint64_t& aGroup) +{ + uint16_t grouptype = (aGroup >> 43) & 0x1F; + if (!(mRDSGroupMask & (1 << grouptype))) { + return true; + } + + mRDSGroupSet = true; + mRDSGroup = aGroup; + NotifyFMRadioEvent(NewRDSGroup); + return true; +} + +bool FMRadioChild::Recv__delete__() { return true; } PFMRadioRequestChild* FMRadioChild::AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs) {
--- a/dom/fmradio/ipc/FMRadioChild.h +++ b/dom/fmradio/ipc/FMRadioChild.h @@ -29,29 +29,38 @@ public: static FMRadioChild* Singleton(); ~FMRadioChild(); void SendRequest(FMRadioReplyRunnable* aReplyRunnable, FMRadioRequestArgs aArgs); /* IFMRadioService */ virtual bool IsEnabled() const MOZ_OVERRIDE; + virtual bool IsRDSEnabled() 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 Nullable<unsigned short> GetPi() const MOZ_OVERRIDE; + virtual Nullable<uint8_t> GetPty() const MOZ_OVERRIDE; + virtual bool GetPs(nsString& aPSName) MOZ_OVERRIDE; + virtual bool GetRt(nsString& aRadiotext) MOZ_OVERRIDE; + virtual bool GetRdsgroup(uint64_t& aRDSGroup) MOZ_OVERRIDE; virtual void Enable(double aFrequency, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void Disable(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void SetFrequency(double frequency, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection, FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void CancelSeek(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; + virtual void SetRDSGroupMask(uint32_t aRDSGroupMask) MOZ_OVERRIDE; + virtual void EnableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; + virtual void DisableRDS(FMRadioReplyRunnable* aReplyRunnable) MOZ_OVERRIDE; virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE; virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE; virtual void EnableAudio(bool aAudioEnabled) MOZ_OVERRIDE; /* PFMRadioChild */ virtual bool @@ -59,34 +68,64 @@ public: virtual bool RecvNotifyFrequencyChanged(const double& aFrequency) MOZ_OVERRIDE; virtual bool RecvNotifyEnabledChanged(const bool& aEnabled, const double& aFrequency) MOZ_OVERRIDE; + virtual bool + RecvNotifyRDSEnabledChanged(const bool& aEnabled) MOZ_OVERRIDE; + + virtual bool + RecvNotifyPIChanged(const bool& aValid, + const uint16_t& aCode) MOZ_OVERRIDE; + + virtual bool + RecvNotifyPTYChanged(const bool& aValid, + const uint8_t& aPTY) MOZ_OVERRIDE; + + virtual bool + RecvNotifyPSChanged(const nsString& aPSName) MOZ_OVERRIDE; + + virtual bool + RecvNotifyRadiotextChanged(const nsString& aRadiotext) MOZ_OVERRIDE; + + virtual bool + RecvNotifyNewRDSGroup(const uint64_t& aGroup) MOZ_OVERRIDE; + virtual PFMRadioRequestChild* AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs) MOZ_OVERRIDE; virtual bool DeallocPFMRadioRequestChild(PFMRadioRequestChild* aActor) MOZ_OVERRIDE; private: FMRadioChild(); void Init(); inline void NotifyFMRadioEvent(FMRadioEventType aType); bool mEnabled; + bool mRDSEnabled; + bool mRDSGroupSet; + bool mPSNameSet; + bool mRadiotextSet; double mFrequency; double mUpperBound; double mLowerBound; double mChannelWidth; + Nullable<unsigned short> mPI; + Nullable<uint8_t> mPTY; + nsAutoString mPSName; + nsAutoString mRadiotext; + uint64_t mRDSGroup; + uint32_t mRDSGroupMask; FMRadioEventObserverList mObserverList; private: static StaticAutoPtr<FMRadioChild> sFMRadioChild; }; END_FMRADIO_NAMESPACE
--- a/dom/fmradio/ipc/FMRadioParent.cpp +++ b/dom/fmradio/ipc/FMRadioParent.cpp @@ -1,16 +1,17 @@ /* -*- 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/. */ #include "FMRadioParent.h" #include "mozilla/unused.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/DebugOnly.h" #include "FMRadioRequestParent.h" #include "FMRadioService.h" BEGIN_FMRADIO_NAMESPACE FMRadioParent::FMRadioParent() { MOZ_COUNT_CTOR(FMRadioParent); @@ -64,16 +65,22 @@ FMRadioParent::AllocPFMRadioRequestParen break; case FMRadioRequestArgs::TSeekRequestArgs: IFMRadioService::Singleton()->Seek( aArgs.get_SeekRequestArgs().direction(), requestParent); break; case FMRadioRequestArgs::TCancelSeekRequestArgs: IFMRadioService::Singleton()->CancelSeek(requestParent); break; + case FMRadioRequestArgs::TEnableRDSArgs: + IFMRadioService::Singleton()->EnableRDS(requestParent); + break; + case FMRadioRequestArgs::TDisableRDSArgs: + IFMRadioService::Singleton()->DisableRDS(requestParent); + break; default: MOZ_CRASH(); } // Balanced in DeallocPFMRadioRequestParent return requestParent.forget().take(); } @@ -93,23 +100,67 @@ FMRadioParent::Notify(const FMRadioEvent unused << SendNotifyFrequencyChanged( IFMRadioService::Singleton()->GetFrequency()); break; case EnabledChanged: unused << SendNotifyEnabledChanged( IFMRadioService::Singleton()->IsEnabled(), IFMRadioService::Singleton()->GetFrequency()); break; + case RDSEnabledChanged: + unused << SendNotifyRDSEnabledChanged( + IFMRadioService::Singleton()->IsRDSEnabled()); + break; + case PIChanged: { + Nullable<unsigned short> pi = + IFMRadioService::Singleton()->GetPi(); + unused << SendNotifyPIChanged(!pi.IsNull(), + pi.IsNull() ? 0 : pi.Value()); + break; + } + case PTYChanged: { + Nullable<uint8_t> pty = IFMRadioService::Singleton()->GetPty(); + unused << SendNotifyPTYChanged(!pty.IsNull(), + pty.IsNull() ? 0 : pty.Value()); + break; + } + case PSChanged: { + nsAutoString psname; + IFMRadioService::Singleton()->GetPs(psname); + unused << SendNotifyPSChanged(psname); + break; + } + case RadiotextChanged: { + nsAutoString radiotext; + IFMRadioService::Singleton()->GetRt(radiotext); + unused << SendNotifyRadiotextChanged(radiotext); + break; + } + case NewRDSGroup: { + uint64_t group; + DebugOnly<bool> rdsgroupset = + IFMRadioService::Singleton()->GetRdsgroup(group); + MOZ_ASSERT(rdsgroupset); + unused << SendNotifyNewRDSGroup(group); + break; + } default: NS_RUNTIMEABORT("not reached"); break; } } bool FMRadioParent::RecvEnableAudio(const bool& aAudioEnabled) { IFMRadioService::Singleton()->EnableAudio(aAudioEnabled); return true; } +bool +FMRadioParent::RecvSetRDSGroupMask(const uint32_t& aRDSGroupMask) +{ + IFMRadioService::Singleton()->SetRDSGroupMask(aRDSGroupMask); + return true; +} + END_FMRADIO_NAMESPACE
--- a/dom/fmradio/ipc/FMRadioParent.h +++ b/dom/fmradio/ipc/FMRadioParent.h @@ -34,14 +34,17 @@ public: virtual bool DeallocPFMRadioRequestParent(PFMRadioRequestParent* aActor) MOZ_OVERRIDE; /* FMRadioEventObserver */ virtual void Notify(const FMRadioEventType& aType) MOZ_OVERRIDE; virtual bool RecvEnableAudio(const bool& aAudioEnabled) MOZ_OVERRIDE; + + virtual bool + RecvSetRDSGroupMask(const uint32_t& aRDSGroupMask) MOZ_OVERRIDE; }; END_FMRADIO_NAMESPACE #endif // mozilla_dom_fmradioparent_h__
--- a/dom/fmradio/ipc/PFMRadio.ipdl +++ b/dom/fmradio/ipc/PFMRadio.ipdl @@ -29,23 +29,33 @@ struct SeekRequestArgs { FMRadioSeekDirection direction; }; struct CancelSeekRequestArgs { }; +struct EnableRDSArgs +{ +}; + +struct DisableRDSArgs +{ +}; + union FMRadioRequestArgs { EnableRequestArgs; DisableRequestArgs; SetFrequencyRequestArgs; SeekRequestArgs; CancelSeekRequestArgs; + EnableRDSArgs; + DisableRDSArgs; }; struct StatusInfo { bool enabled; double frequency; double upperBound; double lowerBound; @@ -61,16 +71,40 @@ child: /** * Sent when the frequency is changed. */ NotifyFrequencyChanged(double frequency); /** * Sent when the power state of FM radio HW is changed. */ NotifyEnabledChanged(bool enabled, double frequency); + /** + * Sent when RDS is enabled or disabled. + */ + NotifyRDSEnabledChanged(bool enabled); + /** + * Sent when we have a new PI code. + */ + NotifyPIChanged(bool valid, uint16_t code); + /** + * Sent when we have a new PTY + */ + NotifyPTYChanged(bool valid, uint8_t pty); + /** + * Sent when we have a new PS name. + */ + NotifyPSChanged(nsString psname); + /** + * Sent when we have new radiotext. + */ + NotifyRadiotextChanged(nsString radiotext); + /** + * Sent when a full RDS group is received. + */ + NotifyNewRDSGroup(uint64_t data); __delete__(); parent: /** * Get the current status infomation of FM radio HW synchronously. * Sent when the singleton object of FMRadioChild is initialized. */ @@ -86,13 +120,18 @@ parent: * is more error prone. */ PFMRadioRequest(FMRadioRequestArgs requestType); /** * Enable/Disable audio */ EnableAudio(bool audioEnabled); + + /** + * Set RDS group mask + */ + SetRDSGroupMask(uint32_t groupMask); }; } // namespace dom } // namespace mozilla
--- a/dom/webidl/FMRadio.webidl +++ b/dom/webidl/FMRadio.webidl @@ -1,16 +1,19 @@ /* 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 RDS reception is enabled */ + readonly attribute boolean rdsEnabled; + /* 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; @@ -26,31 +29,92 @@ interface FMRadio : EventTarget { * 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; + /** + * This is a mask consisting of bits corresponding to + * (1 << groupcode) that can be specified to receive + * raw RDS groups of specific group types. Note that + * groupcode corresponds to the upper 5 bits in block B. + */ + attribute unsigned long rdsGroupMask; + + /** + * The Program Identification (PI) code. + * Available if RDS is enabled on both the station and on this device. + * The value is null otherwise. + */ + readonly attribute unsigned short? pi; + + /** + * The Program Type (PTY) code. + * Available if RDS is enabled on both the station and on this device. + * The value is null otherwise. + */ + readonly attribute octet? pty; + + /** + * The Program Service (PS) name. + * Available if RDS is enabled on the station and on this device + */ + readonly attribute DOMString? ps; + + /** + * The radiotext, as provided by group 2A/2B. + * Available if RDS is enabled on the station and on this device + */ + readonly attribute DOMString? rt; + + /** + * The last RDS group received. + * Available if RDS is enabled on the station and on this device + */ + readonly attribute Uint16Array? rdsgroup; + /* Fired when the FM radio is enabled. */ attribute EventHandler onenabled; /* Fired when the FM radio is disabled. */ attribute EventHandler ondisabled; + /* Fired when the RDS is enabled. */ + attribute EventHandler onrdsenabled; + + /* Fired when the RDS is disabled. */ + attribute EventHandler onrdsdisabled; + /** * Fired when the antenna becomes available or unavailable, i.e., fired when * the antennaAvailable attribute changes. */ attribute EventHandler onantennaavailablechange; /* Fired when the FM radio's frequency is changed. */ attribute EventHandler onfrequencychange; + /* Fired when the PI code changes */ + attribute EventHandler onpichange; + + /* Fired when the PTY changes */ + attribute EventHandler onptychange; + + /* Fired when the PS name changes */ + attribute EventHandler onpschange; + + /* Fired when the radiotext changes */ + attribute EventHandler onrtchange; + + /* Fired when we get a new RDS group */ + attribute EventHandler onnewrdsgroup; + /** * 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. @@ -89,10 +153,24 @@ interface FMRadio : EventTarget { */ DOMRequest seekDown(); /** * Cancel the seek action. If the radio is not currently seeking up or down, * error will be fired. */ DOMRequest cancelSeek(); + + /** + * Enable RDS reception. + * + * If the radio is off, RDS will be enabled when the radio is turned on. + */ + DOMRequest enableRDS(); + + /** + * Disable RDS reception. + * + * If the radio is off, RDS will not be enabled when the radio is turned on. + */ + DOMRequest disableRDS(); };