Bug 815452: Hook up FM radio to the audio manager. r=sicking a=blocking-basecamp

This commit is contained in:
Randy Lin ext:(%20and%20Chris%20Jones%20%3Cjones.chris.g%40gmail.com%3E) 2012-12-11 01:13:08 -08:00
parent dc892b3d1e
commit 031981ba1b
5 changed files with 107 additions and 4 deletions

View File

@ -73,6 +73,19 @@ DOMFMRadioChild.prototype = {
"DOMFMRadio:powerStateChange",
"DOMFMRadio:antennaChange"];
this.initHelper(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
@ -130,6 +143,18 @@ DOMFMRadioChild.prototype = {
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) {
@ -153,6 +178,7 @@ DOMFMRadioChild.prototype = {
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;
@ -160,6 +186,10 @@ DOMFMRadioChild.prototype = {
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;
@ -291,6 +321,10 @@ DOMFMRadioChild.prototype = {
},
enable: function nsIDOMFMRadio_enable(frequency) {
// FMRadio::Enable() needs the most recent visibility state
// synchronously.
this._haveEnabledRadio = true;
this._notifyVisibility();
return this._call("enable", frequency);
},

View File

@ -101,7 +101,8 @@ this.DOMFMRadioParent = {
"DOMFMRadio:getPowerState", "DOMFMRadio:getFrequency",
"DOMFMRadio:getAntennaState",
"DOMFMRadio:seekUp", "DOMFMRadio:seekDown",
"DOMFMRadio:cancelSeek"
"DOMFMRadio:cancelSeek",
"DOMFMRadio:updateVisibility",
];
this._messages.forEach(function(msgName) {
ppmm.addMessageListener(msgName, this);
@ -458,6 +459,9 @@ this.DOMFMRadioParent = {
self._sendMessage("DOMFMRadio:cancelSeek:Return", true, null, msg);
}
break;
case "DOMFMRadio:updateVisibility":
FMRadio.updateVisible(msg == 'visible');
break;
}
}
};

View File

@ -38,6 +38,7 @@ using mozilla::Preferences;
FMRadio::FMRadio()
: mHeadphoneState(SWITCH_STATE_OFF)
, mHasInternalAntenna(false)
, mHidden(true)
{
LOG("FMRadio is initialized.");
@ -114,6 +115,23 @@ NS_IMETHODIMP FMRadio::Enable(nsIFMRadioSettings *settings)
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);
// 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.
CanPlayChanged(canPlay);
settings->GetUpperLimit(&upperLimit);
settings->GetLowerLimit(&lowerLimit);
settings->GetChannelWidth(&channelWidth);
@ -140,12 +158,17 @@ NS_IMETHODIMP FMRadio::Disable()
// 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;
}
@ -189,6 +212,15 @@ NS_IMETHODIMP FMRadio::SetFrequency(int32_t 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()) {
@ -211,5 +243,27 @@ void FMRadio::Notify(const FMRadioOperationInformation& info)
case FM_RADIO_OPERATION_SEEK:
DispatchTrustedEvent(RADIO_SEEK_COMPLETE_EVENT_NAME);
break;
default:
MOZ_NOT_REACHED();
return;
}
}
/* 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);
/* mute fm first, it should be better to stop&resume fm */
if (canPlay) {
int32_t volIdx = 0;
// Restore fm volume, that value is sync as music type
audioManager->GetStreamVolumeIndex(nsIAudioManager::STREAM_TYPE_MUSIC, &volIdx);
audioManager->SetStreamVolumeIndex(nsIAudioManager::STREAM_TYPE_FM, volIdx);
} else {
audioManager->SetStreamVolumeIndex(nsIAudioManager::STREAM_TYPE_FM, 0);
}
return NS_OK;
}

View File

@ -11,6 +11,7 @@
#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
@ -26,10 +27,12 @@ class FMRadio : public nsDOMEventTargetHelper
, public nsIFMRadio
, public hal::FMRadioObserver
, public hal::SwitchObserver
, public nsIAudioChannelAgentCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFMRADIO
NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
@ -41,8 +44,11 @@ public:
private:
~FMRadio();
bool mHasInternalAntenna;
hal::SwitchState mHeadphoneState;
bool mHasInternalAntenna;
bool mHidden;
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
};
} // namespace fm

View File

@ -26,7 +26,7 @@ interface nsIFMRadioSettings : nsISupports
*
* If the WebFM API is re-written in c++ some day, this interface will be useless.
*/
[scriptable, builtinclass, uuid(26288adc-d2c1-4fbc-86b5-ecd8173fbf90)]
[scriptable, builtinclass, uuid(9586bc9c-738e-4bcd-907c-ad340a6adc8b)]
interface nsIFMRadio : nsIDOMEventTarget {
const long SEEK_DIRECTION_UP = 0;
const long SEEK_DIRECTION_DOWN = 1;
@ -79,6 +79,11 @@ interface nsIFMRadio : nsIDOMEventTarget {
*/
void setFrequency(in long frequency);
/**
* Update the visibility state of our client.
*/
void updateVisible(in boolean visible);
/**
* Fired when the antenna state is changed.
*/