Backed out 8 changesets (bug 1113086) for build bustage

Backed out changeset a20839dfd439 (bug 1113086)
Backed out changeset 675ea719b91c (bug 1113086)
Backed out changeset cfb34138bb9f (bug 1113086)
Backed out changeset b9525c60a737 (bug 1113086)
Backed out changeset 380859ae955b (bug 1113086)
Backed out changeset 5ec088f0892f (bug 1113086)
Backed out changeset caf57ae8cbce (bug 1113086)
Backed out changeset 0fc4dec6cd81 (bug 1113086)

--HG--
extra : histedit_source : d8dfd75d9dae36b7309ce78e3b4488faf57003da%2C48081711b7067191d8e4749fd3b572db59bc03f9
This commit is contained in:
Xidorn Quan 2015-07-11 10:55:59 +10:00
Родитель 291696aa87
Коммит f23d866f51
77 изменённых файлов: 3106 добавлений и 2054 удалений

Просмотреть файл

@ -888,8 +888,6 @@ bin/libfreebl_32int64_3.so
@RESPATH@/components/DataStoreImpl.js
@RESPATH@/components/dom_datastore.xpt
@RESPATH@/components/dom_audiochannel.xpt
; Shutdown Terminator
@RESPATH@/components/nsTerminatorTelemetry.js
@RESPATH@/components/terminator.manifest

Просмотреть файл

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioChannelAgent.h"
#include "AudioChannelCommon.h"
#include "AudioChannelService.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
@ -25,6 +26,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
AudioChannelAgent::AudioChannelAgent()
: mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
, mIsRegToService(false)
, mVisible(true)
, mWithVideo(false)
{
}
@ -63,10 +66,21 @@ AudioChannelAgent::InitWithWeakCallback(nsIDOMWindow* aWindow,
/* useWeakRef = */ true);
}
/* void initWithVideo(in nsIDOMWindow window, in long channelType,
* in nsIAudioChannelAgentCallback callback, in boolean weak); */
NS_IMETHODIMP
AudioChannelAgent::InitWithVideo(nsIDOMWindow* aWindow, int32_t aChannelType,
nsIAudioChannelAgentCallback *aCallback,
bool aUseWeakRef)
{
return InitInternal(aWindow, aChannelType, aCallback, aUseWeakRef,
/* withVideo = */ true);
}
nsresult
AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
nsIAudioChannelAgentCallback *aCallback,
bool aUseWeakRef)
bool aUseWeakRef, bool aWithVideo)
{
// We syncd the enum of channel type between nsIAudioChannelAgent.idl and
// AudioChannelBinding.h the same.
@ -86,16 +100,12 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
}
if (aWindow) {
nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
MOZ_ASSERT(topWindow);
mWindow = do_QueryInterface(topWindow);
if (!mWindow) {
return NS_ERROR_FAILURE;
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow);
if (!pWindow->IsInnerWindow()) {
pWindow = pWindow->GetCurrentInnerWindow();
}
mWindow = mWindow->GetOuterWindow();
mWindow = pWindow.forget();
}
mAudioChannelType = aChannelType;
@ -106,26 +116,23 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
mCallback = aCallback;
}
mWithVideo = aWithVideo;
return NS_OK;
}
/* boolean startPlaying (); */
NS_IMETHODIMP AudioChannelAgent::StartPlaying(float *aVolume, bool* aMuted)
NS_IMETHODIMP AudioChannelAgent::StartPlaying(int32_t *_retval)
{
MOZ_ASSERT(aVolume);
MOZ_ASSERT(aMuted);
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
AudioChannelService *service = AudioChannelService::GetOrCreateAudioChannelService();
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
service == nullptr || mIsRegToService) {
return NS_ERROR_FAILURE;
}
service->RegisterAudioChannelAgent(this,
static_cast<AudioChannel>(mAudioChannelType));
service->GetState(mWindow, mAudioChannelType, aVolume, aMuted);
static_cast<AudioChannel>(mAudioChannelType), mWithVideo);
*_retval = service->GetState(this, !mVisible);
mIsRegToService = true;
return NS_OK;
}
@ -138,12 +145,36 @@ NS_IMETHODIMP AudioChannelAgent::StopPlaying(void)
return NS_ERROR_FAILURE;
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
AudioChannelService *service = AudioChannelService::GetOrCreateAudioChannelService();
service->UnregisterAudioChannelAgent(this);
mIsRegToService = false;
return NS_OK;
}
/* void setVisibilityState (in boolean visible); */
NS_IMETHODIMP AudioChannelAgent::SetVisibilityState(bool visible)
{
bool oldVisibility = mVisible;
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
mVisible = visible;
if (mIsRegToService && oldVisibility != mVisible && callback) {
AudioChannelService *service = AudioChannelService::GetOrCreateAudioChannelService();
callback->CanPlayChanged(service->GetState(this, !mVisible));
}
return NS_OK;
}
void AudioChannelAgent::NotifyAudioChannelStateChanged()
{
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
if (callback) {
AudioChannelService *service = AudioChannelService::GetOrCreateAudioChannelService();
callback->CanPlayChanged(service->GetState(this, !mVisible));
}
}
already_AddRefed<nsIAudioChannelAgentCallback>
AudioChannelAgent::GetCallback()
{
@ -162,17 +193,20 @@ AudioChannelAgent::WindowVolumeChanged()
return;
}
float volume = 1.0;
bool muted = false;
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
service->GetState(mWindow, mAudioChannelType, &volume, &muted);
callback->WindowVolumeChanged(volume, muted);
callback->WindowVolumeChanged();
}
uint64_t
AudioChannelAgent::WindowID() const
NS_IMETHODIMP
AudioChannelAgent::GetWindowVolume(float* aVolume)
{
return mWindow ? mWindow->WindowID() : 0;
NS_ENSURE_ARG_POINTER(aVolume);
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mWindow);
if (!win) {
*aVolume = 1.0f;
return NS_OK;
}
*aVolume = win->GetAudioGlobalVolume();
return NS_OK;
}

Просмотреть файл

@ -17,7 +17,7 @@
#define NS_AUDIOCHANNELAGENT_CID {0xf27688e2, 0x3dd7, 0x11e2, \
{0x90, 0x4e, 0x10, 0xbf, 0x48, 0xd6, 0x4b, 0xd4}}
class nsPIDOMWindow;
class nsIDOMWindow;
namespace mozilla {
namespace dom {
@ -32,16 +32,15 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
AudioChannelAgent();
virtual void NotifyAudioChannelStateChanged();
void WindowVolumeChanged();
nsPIDOMWindow* Window() const
nsIDOMWindow* Window() const
{
return mWindow;
}
uint64_t WindowID() const;
private:
virtual ~AudioChannelAgent();
@ -51,18 +50,18 @@ private:
nsresult InitInternal(nsIDOMWindow* aWindow, int32_t aAudioAgentType,
nsIAudioChannelAgentCallback* aCallback,
bool aUseWeakRef);
bool aUseWeakRef, bool aWithVideo=false);
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIDOMWindow> mWindow;
nsCOMPtr<nsIAudioChannelAgentCallback> mCallback;
nsWeakPtr mWeakCallback;
int32_t mAudioChannelType;
bool mIsRegToService;
bool mVisible;
bool mWithVideo;
};
} // namespace dom
} // namespace mozilla
#endif

Просмотреть файл

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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_audiochannelcommon_h__
#define mozilla_dom_audiochannelcommon_h__
namespace mozilla {
namespace dom {
enum AudioChannelState {
AUDIO_CHANNEL_STATE_NORMAL = 0,
AUDIO_CHANNEL_STATE_MUTED,
AUDIO_CHANNEL_STATE_FADED,
AUDIO_CHANNEL_STATE_LAST
};
} // namespace dom
} // namespace mozilla
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -7,14 +7,15 @@
#ifndef mozilla_dom_audiochannelservice_h__
#define mozilla_dom_audiochannelservice_h__
#include "nsIAudioChannelService.h"
#include "nsAutoPtr.h"
#include "nsIObserver.h"
#include "nsTObserverArray.h"
#include "nsTArray.h"
#include "nsITimer.h"
#include "AudioChannelCommon.h"
#include "AudioChannelAgent.h"
#include "nsAttrValue.h"
#include "nsClassHashtable.h"
#include "mozilla/dom/AudioChannelBinding.h"
class nsIRunnable;
@ -25,74 +26,71 @@ namespace dom {
#ifdef MOZ_WIDGET_GONK
class SpeakerManagerService;
#endif
#define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::Publicnotification + 1
class AudioChannelService final : public nsIAudioChannelService
, public nsIObserver
class AudioChannelService
: public nsIObserver
, public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIAUDIOCHANNELSERVICE
NS_DECL_NSITIMERCALLBACK
/**
* Returns the AudioChannelServce singleton or null if the process havn't create it before.
* Only to be called from main thread.
*/
static AudioChannelService* GetAudioChannelService();
/**
* Returns the AudioChannelServce singleton.
* If AudioChannelServce is not exist, create and return new one.
* Only to be called from main thread.
*/
static already_AddRefed<AudioChannelService> GetOrCreate();
static AudioChannelService* GetOrCreateAudioChannelService();
/**
* Shutdown the singleton.
*/
static void Shutdown();
static bool IsAudioChannelMutedByDefault();
/**
* Any audio channel agent that starts playing should register itself to
* this service, sharing the AudioChannel.
*/
void RegisterAudioChannelAgent(AudioChannelAgent* aAgent, AudioChannel aChannel);
virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannel aChannel,
bool aWithVideo);
/**
* Any audio channel agent that stops playing should unregister itself to
* this service.
*/
void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
/**
* Return the state to indicate this audioChannel for his window should keep
* playing/muted.
* Return the state to indicate this agent should keep playing/
* fading volume/muted.
*/
void GetState(nsPIDOMWindow* aWindow, uint32_t aChannel,
float* aVolume, bool* aMuted);
virtual AudioChannelState GetState(AudioChannelAgent* aAgent,
bool aElementHidden);
/* Methods for the BrowserElementAudioChannel */
float GetAudioChannelVolume(nsPIDOMWindow* aWindow, AudioChannel aChannel);
void SetAudioChannelVolume(nsPIDOMWindow* aWindow, AudioChannel aChannel,
float aVolume);
bool GetAudioChannelMuted(nsPIDOMWindow* aWindow, AudioChannel aChannel);
void SetAudioChannelMuted(nsPIDOMWindow* aWindow, AudioChannel aChannel,
bool aMuted);
bool IsAudioChannelActive(nsPIDOMWindow* aWindow, AudioChannel aChannel);
/**
* Return true if there is a content channel active in this process
* or one of its subprocesses.
*/
virtual bool ContentOrNormalChannelIsActive();
/**
* Return true if there is a telephony channel active in this process
* or one of its subprocesses.
*/
bool TelephonyChannelIsActive();
virtual bool TelephonyChannelIsActive();
/**
* Return true if a normal or content channel is active for the given
* process ID.
*/
bool ProcessContentOrNormalChannelIsActive(uint64_t aChildID);
virtual bool ProcessContentOrNormalChannelIsActive(uint64_t aChildID);
/***
* AudioChannelManager calls this function to notify the default channel used
@ -127,94 +125,162 @@ public:
static void GetAudioChannelString(AudioChannel aChannel, nsAString& aString);
static void GetDefaultAudioChannelString(nsAString& aString);
void Notify(uint64_t aWindowID);
void Notify();
void ChildStatusReceived(uint64_t aChildID, bool aTelephonyChannel,
bool aContentOrNormalChannel, bool aAnyChannel);
protected:
void SendNotification();
private:
AudioChannelService();
~AudioChannelService();
/**
* Send the audio-channel-changed notification for the given process ID if
* needed.
*/
void SendAudioChannelChangedNotification(uint64_t aChildID);
void MaybeSendStatusUpdate();
/* Register/Unregister IPC types: */
void RegisterType(AudioChannel aChannel, uint64_t aChildID, bool aWithVideo);
void UnregisterType(AudioChannel aChannel, bool aElementHidden,
uint64_t aChildID, bool aWithVideo);
void UnregisterTypeInternal(AudioChannel aChannel, bool aElementHidden,
uint64_t aChildID, bool aWithVideo);
bool ContentOrNormalChannelIsActive();
AudioChannelState GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
bool aElementHidden,
bool aElementWasHidden);
/* Update the internal type value following the visibility changes */
void UpdateChannelType(AudioChannel aChannel, uint64_t aChildID,
bool aElementHidden, bool aElementWasHidden);
/* Send the default-volume-channel-changed notification */
void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
bool aVisible, uint64_t aChildID);
struct AudioChannelConfig final
{
AudioChannelConfig()
: mVolume(1.0)
, mMuted(IsAudioChannelMutedByDefault())
, mNumberOfAgents(0)
{}
AudioChannelState CheckTelephonyPolicy(AudioChannel aChannel,
uint64_t aChildID);
void RegisterTelephonyChild(uint64_t aChildID);
void UnregisterTelephonyChild(uint64_t aChildID);
float mVolume;
bool mMuted;
AudioChannelService();
virtual ~AudioChannelService();
uint32_t mNumberOfAgents;
enum AudioChannelInternalType {
AUDIO_CHANNEL_INT_NORMAL = 0,
AUDIO_CHANNEL_INT_NORMAL_HIDDEN,
AUDIO_CHANNEL_INT_CONTENT,
AUDIO_CHANNEL_INT_CONTENT_HIDDEN,
AUDIO_CHANNEL_INT_NOTIFICATION,
AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN,
AUDIO_CHANNEL_INT_ALARM,
AUDIO_CHANNEL_INT_ALARM_HIDDEN,
AUDIO_CHANNEL_INT_TELEPHONY,
AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN,
AUDIO_CHANNEL_INT_RINGER,
AUDIO_CHANNEL_INT_RINGER_HIDDEN,
AUDIO_CHANNEL_INT_PUBLICNOTIFICATION,
AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN,
AUDIO_CHANNEL_INT_LAST
};
struct AudioChannelWindow final
{
explicit AudioChannelWindow(uint64_t aWindowID)
: mWindowID(aWindowID)
bool ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType);
bool CheckVolumeFadedCondition(AudioChannelInternalType aType,
bool aElementHidden);
AudioChannelInternalType GetInternalType(AudioChannel aChannel,
bool aElementHidden);
class AudioChannelAgentData {
public:
AudioChannelAgentData(AudioChannel aChannel,
bool aElementHidden,
AudioChannelState aState,
bool aWithVideo)
: mChannel(aChannel)
, mElementHidden(aElementHidden)
, mState(aState)
, mWithVideo(aWithVideo)
{}
uint64_t mWindowID;
AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS];
// Raw pointer because the AudioChannelAgent must unregister itself.
nsTObserverArray<AudioChannelAgent*> mAgents;
AudioChannel mChannel;
bool mElementHidden;
AudioChannelState mState;
const bool mWithVideo;
};
AudioChannelWindow*
GetOrCreateWindowData(nsPIDOMWindow* aWindow);
static PLDHashOperator
NotifyEnumerator(AudioChannelAgent* aAgent,
AudioChannelAgentData* aData, void *aUnused);
AudioChannelWindow*
GetWindowData(uint64_t aWindowID) const;
static PLDHashOperator
RefreshAgentsVolumeEnumerator(AudioChannelAgent* aAgent,
AudioChannelAgentData* aUnused,
void *aPtr);
struct AudioChannelChildStatus final
{
explicit AudioChannelChildStatus(uint64_t aChildID)
: mChildID(aChildID)
, mActiveTelephonyChannel(false)
, mActiveContentOrNormalChannel(false)
{}
static PLDHashOperator
CountWindowEnumerator(AudioChannelAgent* aAgent,
AudioChannelAgentData* aUnused,
void *aPtr);
uint64_t mChildID;
bool mActiveTelephonyChannel;
bool mActiveContentOrNormalChannel;
};
static PLDHashOperator
WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
nsAutoPtr<AudioChannelAgentData>& aData,
void *aPtr);
AudioChannelChildStatus*
GetChildStatus(uint64_t aChildID) const;
void
RemoveChildStatus(uint64_t aChildID);
nsTObserverArray<nsAutoPtr<AudioChannelWindow>> mWindows;
nsTObserverArray<nsAutoPtr<AudioChannelChildStatus>> mPlayingChildren;
// This returns the number of agents from this aWindow.
uint32_t CountWindow(nsIDOMWindow* aWindow);
nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
#ifdef MOZ_WIDGET_GONK
nsTArray<SpeakerManagerService*> mSpeakerManager;
#endif
nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
int32_t mCurrentHigherChannel;
int32_t mCurrentVisibleHigherChannel;
nsTArray<uint64_t> mWithVideoChildIDs;
// Telephony Channel policy is "LIFO", the last app to require the resource is
// allowed to play. The others are muted.
struct TelephonyChild {
uint64_t mChildID;
uint32_t mInstances;
explicit TelephonyChild(uint64_t aChildID)
: mChildID(aChildID)
, mInstances(1)
{}
};
nsTArray<TelephonyChild> mTelephonyChildren;
// mPlayableHiddenContentChildID stores the ChildID of the process which can
// play content channel(s) in the background.
// A background process contained content channel(s) will become playable:
// 1. When this background process registers its content channel(s) in
// AudioChannelService and there is no foreground process with registered
// content channel(s).
// 2. When this process goes from foreground into background and there is
// no foreground process with registered content channel(s).
// A background process contained content channel(s) will become non-playable:
// 1. When there is a foreground process registering its content channel(s)
// in AudioChannelService.
// ps. Currently this condition is never satisfied because the default value
// of visibility status of each channel during registering is hidden = true.
// 2. When there is a process with registered content channel(s) goes from
// background into foreground.
// 3. When this process unregisters all hidden content channels.
// 4. When this process shuts down.
uint64_t mPlayableHiddenContentChildID;
bool mDisabled;
nsCOMPtr<nsIRunnable> mRunnable;
uint64_t mDefChannelChildID;
nsCOMPtr<nsITimer> mDeferTelChannelTimer;
bool mTimerElementHidden;
uint64_t mTimerChildID;
// These boolean are used to know if we have to send an status update to the
// service running in the main process.
bool mTelephonyChannel;
bool mContentOrNormalChannel;
bool mAnyChannel;
uint64_t mDefChannelChildID;
// This is needed for IPC comunication between
// AudioChannelServiceChild and this class.

Просмотреть файл

@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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 "AudioChannelServiceChild.h"
#include "base/basictypes.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/unused.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
#ifdef MOZ_WIDGET_GONK
#include "SpeakerManagerService.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::hal;
StaticRefPtr<AudioChannelServiceChild> gAudioChannelServiceChild;
// static
AudioChannelService*
AudioChannelServiceChild::GetAudioChannelService()
{
MOZ_ASSERT(NS_IsMainThread());
return gAudioChannelServiceChild;
}
// static
AudioChannelService*
AudioChannelServiceChild::GetOrCreateAudioChannelService()
{
MOZ_ASSERT(NS_IsMainThread());
// If we already exist, exit early
if (gAudioChannelServiceChild) {
return gAudioChannelServiceChild;
}
// Create new instance, register, return
nsRefPtr<AudioChannelServiceChild> service = new AudioChannelServiceChild();
MOZ_ASSERT(service);
gAudioChannelServiceChild = service;
return gAudioChannelServiceChild;
}
void
AudioChannelServiceChild::Shutdown()
{
if (gAudioChannelServiceChild) {
gAudioChannelServiceChild = nullptr;
}
}
AudioChannelServiceChild::AudioChannelServiceChild()
{
}
AudioChannelServiceChild::~AudioChannelServiceChild()
{
}
AudioChannelState
AudioChannelServiceChild::GetState(AudioChannelAgent* aAgent, bool aElementHidden)
{
AudioChannelAgentData* data;
if (!mAgents.Get(aAgent, &data)) {
return AUDIO_CHANNEL_STATE_MUTED;
}
AudioChannelState state = AUDIO_CHANNEL_STATE_MUTED;
bool oldElementHidden = data->mElementHidden;
UpdateChannelType(data->mChannel, CONTENT_PROCESS_ID_MAIN, aElementHidden,
oldElementHidden);
// Update visibility.
data->mElementHidden = aElementHidden;
ContentChild* cc = ContentChild::GetSingleton();
cc->SendAudioChannelGetState(data->mChannel, aElementHidden, oldElementHidden,
&state);
data->mState = state;
cc->SendAudioChannelChangedNotification();
#ifdef MOZ_WIDGET_GONK
/** Only modify the speaker status when
* (1) apps in the foreground.
* (2) apps in the backgrund and inactive.
* Notice : modify only when the visible status is stable, because there
* has lantency in passing the visibility events.
**/
bool active = AnyAudioChannelIsActive();
if (aElementHidden == oldElementHidden &&
(!aElementHidden || (aElementHidden && !active))) {
for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
mSpeakerManager[i]->SetAudioChannelActive(active);
}
}
#endif
return state;
}
void
AudioChannelServiceChild::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannel aChannel,
bool aWithVideo)
{
AudioChannelService::RegisterAudioChannelAgent(aAgent, aChannel, aWithVideo);
ContentChild::GetSingleton()->SendAudioChannelRegisterType(aChannel, aWithVideo);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
}
}
void
AudioChannelServiceChild::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
{
AudioChannelAgentData *pData;
if (!mAgents.Get(aAgent, &pData)) {
return;
}
// We need to keep a copy because unregister will remove the
// AudioChannelAgentData object from the hashtable.
AudioChannelAgentData data(*pData);
AudioChannelService::UnregisterAudioChannelAgent(aAgent);
ContentChild::GetSingleton()->SendAudioChannelUnregisterType(
data.mChannel, data.mElementHidden, data.mWithVideo);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
}
#ifdef MOZ_WIDGET_GONK
bool active = AnyAudioChannelIsActive();
for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
mSpeakerManager[i]->SetAudioChannelActive(active);
}
#endif
}
void
AudioChannelServiceChild::SetDefaultVolumeControlChannel(int32_t aChannel,
bool aHidden)
{
ContentChild *cc = ContentChild::GetSingleton();
if (cc) {
cc->SendAudioChannelChangeDefVolChannel(aChannel, aHidden);
}
}

Просмотреть файл

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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_audiochannelservicechild_h__
#define mozilla_dom_audiochannelservicechild_h__
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "AudioChannelService.h"
#include "AudioChannelCommon.h"
namespace mozilla {
namespace dom {
class AudioChannelServiceChild : public AudioChannelService
{
public:
/**
* Returns the AudioChannelServce singleton or null if the process havn't create it before.
* Only to be called from main thread.
*/
static AudioChannelService* GetAudioChannelService();
/**
* Returns the AudioChannelServce singleton.
* If AudioChannelServce is not exist, create and return new one.
* Only to be called from main thread.
*/
static AudioChannelService* GetOrCreateAudioChannelService();
static void Shutdown();
virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannel aChannel,
bool aWithVideo);
virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
/**
* Return the state to indicate this agent should keep playing/
* fading volume/muted.
*/
virtual AudioChannelState GetState(AudioChannelAgent* aAgent,
bool aElementHidden);
virtual void SetDefaultVolumeControlChannel(int32_t aChannel,
bool aHidden);
protected:
AudioChannelServiceChild();
virtual ~AudioChannelServiceChild();
};
} // namespace dom
} // namespace mozilla
#endif

Просмотреть файл

@ -4,21 +4,25 @@
# 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/.
TEST_DIRS += ['tests']
XPIDL_SOURCES += [
'nsIAudioChannelAgent.idl',
'nsIAudioChannelService.idl',
]
XPIDL_MODULE = 'dom_audiochannel'
EXPORTS += [
'AudioChannelAgent.h',
'AudioChannelCommon.h',
'AudioChannelService.h',
'AudioChannelServiceChild.h',
]
UNIFIED_SOURCES += [
'AudioChannelAgent.cpp',
'AudioChannelService.cpp',
'AudioChannelServiceChild.cpp',
]
FAIL_ON_WARNINGS = True

Просмотреть файл

@ -6,13 +6,24 @@
interface nsIDOMWindow;
[uuid(4f537c88-3722-4946-9a09-ce559fa0591d)]
[uuid(194b55d9-39c0-45c6-b8ef-b8049f978ea5)]
interface nsIAudioChannelAgentCallback : nsISupports
{
/**
* Notified when the playable status of channel is changed.
*
* @param canPlay
* Callback from agent to notify component of the playable status
* of the channel. If canPlay is muted state, component SHOULD stop
* playing media associated with this channel as soon as possible. if
* it is faded state then the volume of media should be reduced.
*/
void canPlayChanged(in long canPlay);
/**
* Notified when the window volume/mute is changed
*/
void windowVolumeChanged(in float aVolume, in bool aMuted);
void windowVolumeChanged();
};
/**
@ -29,7 +40,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
* 1. Changes to the playable status of this channel.
*/
[uuid(11138a74-ee64-4a91-9457-f60a5f4527c1)]
[uuid(2b0222a5-8f7b-49d2-9ab8-cd01b744b23e)]
interface nsIAudioChannelAgent : nsISupports
{
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
@ -51,13 +62,6 @@ interface nsIAudioChannelAgent : nsISupports
*/
readonly attribute long audioChannelType;
%{C++
inline int32_t AudioChannelType() {
int32_t channel;
return NS_SUCCEEDED(GetAudioChannelType(&channel)) ? channel : AUDIO_AGENT_CHANNEL_ERROR;
}
%}
/**
* Initialize the agent with a channel type.
* Note: This function should only be called once.
@ -87,6 +91,16 @@ interface nsIAudioChannelAgent : nsISupports
void initWithWeakCallback(in nsIDOMWindow window, in long channelType,
in nsIAudioChannelAgentCallback callback);
/**
* This method is just like init(), and specify the channel is associated
* with video.
*
* @param weak
* true if weak reference should be hold.
*/
void initWithVideo(in nsIDOMWindow window, in long channelType,
in nsIAudioChannelAgentCallback callback, in boolean weak);
/**
* Notify the agent that we want to start playing.
* Note: Gecko component SHOULD call this function first then start to
@ -101,7 +115,7 @@ interface nsIAudioChannelAgent : nsISupports
* faded state: the agent has registered with audio channel service the
* component should start playback as well as reducing the volume.
*/
void startPlaying(out float volume, out bool muted);
long startPlaying();
/**
* Notify the agent we no longer want to play.
@ -112,4 +126,17 @@ interface nsIAudioChannelAgent : nsISupports
* channel service.
*/
void stopPlaying();
/**
* Notify the agent of the visibility state of the window using this agent.
* @param visible
* True if the window associated with the agent is visible.
*/
void setVisibilityState(in boolean visible);
/**
* Retrieve the volume from the window.
*/
readonly attribute float windowVolume;
};

Просмотреть файл

@ -1,29 +0,0 @@
/* -*- Mode: IDL; 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 "nsISupports.idl"
interface nsIDOMWindow;
[scriptable, builtinclass, uuid(323e5472-b8f4-4288-b1b9-53c7c54bbbe8)]
interface nsIAudioChannelService : nsISupports
{
float getAudioChannelVolume(in nsIDOMWindow window,
in unsigned short audioChannel);
void setAudioChannelVolume(in nsIDOMWindow window,
in unsigned short audioChannel,
in float volume);
boolean getAudioChannelMuted(in nsIDOMWindow window,
in unsigned short audioChannel);
void setAudioChannelMuted(in nsIDOMWindow window,
in unsigned short audioChannel,
in boolean muted);
boolean isAudioChannelActive(in nsIDOMWindow window,
in unsigned short audioChannel);
};

Просмотреть файл

@ -0,0 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
const { Services } = Cu.import('resource://gre/modules/Services.jsm');
const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm');
addMessageListener('init-chrome-event', function(message) {
// listen mozChromeEvent and forward to content process.
let type = message.type;
SystemAppProxy.addEventListener('mozChromeEvent', function(event) {
let details = event.detail;
if (details.type === type) {
sendAsyncMessage('chrome-event', details);
}
}, true);
});

Просмотреть файл

@ -0,0 +1,669 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
#ifdef XP_WIN
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "TestHarness.h"
#include "nsWeakReference.h"
#include "AudioChannelService.h"
#include "AudioChannelAgent.h"
#include "nsThreadUtils.h"
#define TEST_ENSURE_BASE(_test, _msg) \
PR_BEGIN_MACRO \
if (!(_test)) { \
fail(_msg); \
return NS_ERROR_FAILURE; \
} else { \
passed(_msg); \
} \
PR_END_MACRO
using namespace mozilla::dom;
void
spin_events_loop_until_false(const bool* const aCondition)
{
nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
nsresult rv = NS_OK;
bool processed = true;
while (*aCondition && NS_SUCCEEDED(rv)) {
rv = thread->ProcessNextEvent(true, &processed);
}
}
class Agent : public nsIAudioChannelAgentCallback,
public nsSupportsWeakReference
{
protected:
virtual ~Agent()
{
if (mRegistered) {
StopPlaying();
}
}
public:
NS_DECL_ISUPPORTS
explicit Agent(AudioChannel aChannel)
: mChannel(aChannel)
, mWaitCallback(false)
, mRegistered(false)
, mCanPlay(AUDIO_CHANNEL_STATE_MUTED)
{
mAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
}
nsresult Init(bool video=false)
{
nsresult rv = NS_OK;
if (video) {
rv = mAgent->InitWithVideo(nullptr, static_cast<int32_t>(mChannel),
this, true);
}
else {
rv = mAgent->InitWithWeakCallback(nullptr, static_cast<int32_t>(mChannel),
this);
}
NS_ENSURE_SUCCESS(rv, rv);
return mAgent->SetVisibilityState(false);
}
nsresult StartPlaying(AudioChannelState *_ret)
{
if (mRegistered) {
StopPlaying();
}
nsresult rv = mAgent->StartPlaying((int32_t *)_ret);
mRegistered = true;
return rv;
}
nsresult StopPlaying()
{
mRegistered = false;
spin_events_loop_until_false(&mWaitCallback);
return mAgent->StopPlaying();
}
nsresult SetVisibilityState(bool visible)
{
if (mRegistered) {
mWaitCallback = true;
}
return mAgent->SetVisibilityState(visible);
}
NS_IMETHODIMP CanPlayChanged(int32_t canPlay) override
{
mCanPlay = static_cast<AudioChannelState>(canPlay);
mWaitCallback = false;
return NS_OK;
}
NS_IMETHODIMP WindowVolumeChanged() override
{
return NS_OK;
}
nsresult GetCanPlay(AudioChannelState *_ret, bool aWaitCallback = false)
{
if (aWaitCallback) {
mWaitCallback = true;
}
spin_events_loop_until_false(&mWaitCallback);
*_ret = mCanPlay;
return NS_OK;
}
nsCOMPtr<nsIAudioChannelAgent> mAgent;
AudioChannel mChannel;
bool mWaitCallback;
bool mRegistered;
AudioChannelState mCanPlay;
};
NS_IMPL_ISUPPORTS(Agent, nsIAudioChannelAgentCallback,
nsISupportsWeakReference)
nsresult
TestDoubleStartPlaying()
{
nsRefPtr<Agent> agent = new Agent(AudioChannel::Normal);
nsresult rv = agent->Init();
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = agent->mAgent->StartPlaying((int32_t *)&playable);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent->mAgent->StartPlaying((int32_t *)&playable);
TEST_ENSURE_BASE(NS_FAILED(rv),
"Test0: StartPlaying calling twice must return error");
return NS_OK;
}
nsresult
TestOneNormalChannel()
{
nsRefPtr<Agent> agent = new Agent(AudioChannel::Normal);
nsresult rv = agent->Init();
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = agent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test1: A normal channel unvisible agent must be muted");
rv = agent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test1: A normal channel visible agent must be playable");
return rv;
}
nsresult
TestTwoNormalChannels()
{
nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Normal);
nsresult rv = agent1->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Normal);
rv = agent2->Init();
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = agent1->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test2: A normal channel unvisible agent1 must be muted");
rv = agent2->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test2: A normal channel unvisible agent2 must be muted");
rv = agent1->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test2: A normal channel visible agent1 must be playable");
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test2: A normal channel visible agent2 must be playable");
return rv;
}
nsresult
TestContentChannels()
{
nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Content);
nsresult rv = agent1->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Content);
rv = agent2->Init();
NS_ENSURE_SUCCESS(rv, rv);
// All content channels in the foreground can be allowed to play
rv = agent1->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = agent1->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel visible agent1 must be playable");
rv = agent2->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel visible agent2 must be playable");
// Test the transition state of one content channel tried to set non-visible
// state first when app is going to background.
rv = agent1->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel unvisible agent1 must be playable from "
"foreground to background");
// Test all content channels set non-visible already
rv = agent2->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel unvisible agent2 must be playable from "
"foreground to background");
// Clear the content channels & mActiveContentChildIDs in AudioChannelService.
// If agent stop playable in the background, we will reserve it's childID in
// mActiveContentChildIDs, then it can allow to play next song. So we set agents
// to foreground first then stopping to play
rv = agent1->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->StopPlaying();
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->StopPlaying();
NS_ENSURE_SUCCESS(rv, rv);
// Test that content channels can be allow to play when they starts from
// the background state
rv = agent1->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent2->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel unvisible agent1 must be playable "
"from background state");
rv = agent2->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test3: A content channel unvisible agent2 must be playable "
"from background state");
return rv;
}
nsresult
TestFadedState()
{
nsRefPtr<Agent> normalAgent = new Agent(AudioChannel::Normal);
nsresult rv = normalAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> contentAgent = new Agent(AudioChannel::Content);
rv = contentAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> notificationAgent = new Agent(AudioChannel::Notification);
rv = notificationAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
rv = normalAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = contentAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = notificationAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = normalAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test4: A normal channel visible agent must be playable");
rv = contentAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test4: A content channel visible agent must be playable");
rv = notificationAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test4: A notification channel visible agent must be playable");
rv = contentAgent->GetCanPlay(&playable, true);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_FADED,
"Test4: A content channel unvisible agent must be faded because of "
"notification channel is playing");
rv = contentAgent->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = contentAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_FADED,
"Test4: A content channel unvisible agent must be faded because of "
"notification channel is playing");
rv = notificationAgent->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = notificationAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test4: A notification channel unvisible agent must be playable from "
"foreground to background");
rv = notificationAgent->StopPlaying();
NS_ENSURE_SUCCESS(rv, rv);
rv = contentAgent->GetCanPlay(&playable, true);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test4: A content channel unvisible agent must be playable "
"because of notification channel is stopped");
rv = contentAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
nsresult
TestPriorities()
{
nsRefPtr<Agent> normalAgent = new Agent(AudioChannel::Normal);
nsresult rv = normalAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> contentAgent = new Agent(AudioChannel::Content);
rv = contentAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> notificationAgent = new Agent(AudioChannel::Notification);
rv = notificationAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> alarmAgent = new Agent(AudioChannel::Alarm);
rv = alarmAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> telephonyAgent = new Agent(AudioChannel::Telephony);
rv = telephonyAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> ringerAgent = new Agent(AudioChannel::Ringer);
rv = ringerAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> pNotificationAgent =
new Agent(AudioChannel::Publicnotification);
rv = pNotificationAgent->Init();
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = normalAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test5: A normal channel unvisible agent must be muted");
rv = contentAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A content channel unvisible agent must be playable while "
"playing from background state");
rv = notificationAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A notification channel unvisible agent must be playable");
rv = alarmAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: An alarm channel unvisible agent must be playable");
rv = notificationAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test5: A notification channel unvisible agent must be muted when an "
"alarm is playing");
rv = telephonyAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A telephony channel unvisible agent must be playable");
rv = alarmAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test5: An alarm channel unvisible agent must be muted when a telephony "
"is playing");
rv = ringerAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A ringer channel unvisible agent must be playable");
rv = telephonyAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test5: A telephony channel unvisible agent must be muted when a ringer "
"is playing");
rv = pNotificationAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A pNotification channel unvisible agent must be playable");
rv = ringerAgent->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test5: A ringer channel unvisible agent must be muted when a public "
"notification is playing");
// Stop to play notification channel or normal/content will be faded.
// Which already be tested on Test 4.
rv = notificationAgent->StopPlaying();
NS_ENSURE_SUCCESS(rv, rv);
// Settings visible the normal channel.
rv = normalAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = normalAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A normal channel visible agent must be playable");
// Set the content channel as visible .
rv = contentAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
// Content must be playable because visible.
rv = contentAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A content channel visible agent must be playable");
// Set the alarm channel as visible.
rv = alarmAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = alarmAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: An alarm channel visible agent must be playable");
// Set the telephony channel as visible.
rv = telephonyAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = telephonyAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A telephony channel visible agent must be playable");
// Set the ringer channel as visible.
rv = ringerAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = ringerAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A ringer channel visible agent must be playable");
// Set the public notification channel as visible.
rv = pNotificationAgent->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = pNotificationAgent->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test5: A pNotification channel visible agent must be playable");
return rv;
}
nsresult
TestOneVideoNormalChannel()
{
nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Normal);
nsresult rv = agent1->Init(true);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Content);
rv = agent2->Init(false);
NS_ENSURE_SUCCESS(rv, rv);
AudioChannelState playable;
rv = agent1->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test6: A video normal channel invisible agent1 must be muted");
rv = agent2->StartPlaying(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A content channel invisible agent2 must be playable");
// one video normal channel in foreground and one content channel in background
rv = agent1->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A video normal channel visible agent1 must be playable");
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test6: A content channel invisible agent2 must be muted");
// both one video normal channel and one content channel in foreground
rv = agent2->SetVisibilityState(true);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A video normal channel visible agent1 must be playable");
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A content channel visible agent2 must be playable");
// one video normal channel in background and one content channel in foreground
rv = agent1->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test6: A video normal channel invisible agent1 must be muted");
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A content channel visible agent2 must be playable");
// both one video normal channel and one content channel in background
rv = agent2->SetVisibilityState(false);
NS_ENSURE_SUCCESS(rv, rv);
rv = agent1->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
"Test6: A video normal channel invisible agent1 must be muted");
rv = agent2->GetCanPlay(&playable);
NS_ENSURE_SUCCESS(rv, rv);
TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_NORMAL,
"Test6: A content channel invisible agent2 must be playable");
return rv;
}
int main(int argc, char** argv)
{
ScopedXPCOM xpcom("AudioChannelService");
if (xpcom.failed()) {
return 1;
}
if (NS_FAILED(TestDoubleStartPlaying())) {
return 1;
}
if (NS_FAILED(TestOneNormalChannel())) {
return 1;
}
if (NS_FAILED(TestTwoNormalChannels())) {
return 1;
}
if (NS_FAILED(TestContentChannels())) {
return 1;
}
if (NS_FAILED(TestFadedState())) {
return 1;
}
// Channel type with AudioChannel::Telephony cannot be unregistered until the
// main thread has chances to process 1500 millisecond timer. In order to
// skip ambiguous return value of ChannelsActiveWithHigherPriorityThan(), new
// test cases are added before any test case that registers the channel type
// with AudioChannel::Telephony channel.
if (NS_FAILED(TestOneVideoNormalChannel())) {
return 1;
}
if (NS_FAILED(TestPriorities())) {
return 1;
}
return 0;
}

Двоичные данные
dom/audiochannel/tests/audio.ogg Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test audio-channel-changed & visible-audio-channel-changed mozChromeEvent</title>
</head>
<body>
<div id="content"></div>
<script>
var normalAudio;
var contentAudio;
var notificationAudio;
var alarmAudio;
var telephonyAudio;
var ringerAudio;
var publicnotificationAudio;
function playWithAudioType(audio, type) {
audio.mozAudioChannelType = type;
audio.src = "test.ogg";
audio.loop = true;
audio.play();
}
function runTest() {
// normal channel.
normalAudio = new Audio();
playWithAudioType(normalAudio, 'normal');
// content channel.
contentAudio = new Audio();
playWithAudioType(contentAudio, 'content');
// notification channel.
notificationAudio = new Audio();
playWithAudioType(notificationAudio, 'notification');
// alarm channel.
alarmAudio = new Audio();
playWithAudioType(alarmAudio, 'alarm');
// telephony channel.
telephonyAudio = new Audio();
playWithAudioType(telephonyAudio, 'telephony');
// ringer channel.
ringerAudio = new Audio();
playWithAudioType(ringerAudio, 'ringer');
// publicnotification channel.
publicnotificationAudio = new Audio();
playWithAudioType(publicnotificationAudio, 'publicnotification');
window.addEventListener('hashchange', function(event) {
if (location.hash == "#pauseAudio") {
publicnotificationAudio.pause();
ringerAudio.pause();
telephonyAudio.pause();
}
if (location.hash == "#pauseAudioFollowing") {
alarmAudio.pause();
notificationAudio.pause();
contentAudio.pause();
normalAudio.pause();
}
}, false);
}
function checkBackgroundStatus() {
if (location.hash == "#fg") {
runTest();
return;
}
if (document.hidden) {
runTest();
return;
}
document.addEventListener('visibilitychange', function visibilityChange() {
if (document.hidden) {
runTest();
}
});
}
SpecialPowers.pushPermissions(
[{ "type": "audio-channel-content", "allow": 1, "context": document },
{ "type": "audio-channel-notification", "allow": 1, "context": document },
{ "type": "audio-channel-alarm", "allow": 1, "context": document },
{ "type": "audio-channel-telephony", "allow": 1, "context": document },
{ "type": "audio-channel-ringer", "allow": 1, "context": document },
{ "type": "audio-channel-publicnotification", "allow": 1, "context": document }],
checkBackgroundStatus);
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test Telephony Channel Policy</title>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var audio = new Audio();
audio.mozAudioChannelType = 'telephony';
audio.src = "audio.ogg";
audio.play();
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,11 @@
[DEFAULT]
support-files =
audio.ogg
file_audio.html
file_telephonyPolicy.html
AudioChannelChromeScript.js
[test_telephonyPolicy.html]
skip-if = buildapp == 'mulet' || (toolkit == 'gonk' || e10s) || os == "android"
[test_audioChannelChange.html]
skip-if = (toolkit != 'gonk')

Просмотреть файл

@ -0,0 +1,16 @@
# -*- 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/.
GeckoCppUnitTests([
'TestAudioChannelService',
])
if CONFIG['OS_ARCH'] == 'WINNT':
DEFINES['NOMINMAX'] = True
MOCHITEST_MANIFESTS += ['mochitest.ini']
FAIL_ON_WARNINGS = True

Просмотреть файл

@ -0,0 +1,209 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test audio-channel-changed & visible-audio-channel-changed mozChromeEvent</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
var expectedAudioTypes;
var expectedVisibleAudioTypes;
var expectedVisibleAudioType;
var index;
var visibleIndex;
var iframe1;
var normalAudio;
function playWithAudioType(audio, type) {
audio.mozAudioChannelType = type;
audio.src = "test.ogg";
audio.loop = true;
audio.play();
}
function fgBgTestListener(message) {
var type = message.type;
var channel = message.channel;
if (type == 'audio-channel-changed') {
is(channel, expectedAudioTypes[index], channel + " is received and expected " + expectedAudioTypes[index]);
index++;
}
if (type == 'visible-audio-channel-changed') {
is(channel, expectedVisibleAudioType, channel + " is received and expected " + expectedVisibleAudioType);
}
// All audio types are playing now so ask to pause them.
// This call will stop audio from highest to telephony.
if ('cmd-pause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudio';
index++;
}
// According to there is a 1.5 second delay of releasing telephony,
// we need to wait for it then continue to pause others.
if ('cmd-secondPause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudioFollowing';
index++;
}
if (index == expectedAudioTypes.length) {
document.body.removeChild(iframe1);
script.removeMessageListener('chrome-event', fgBgTestListener);
normalAudio.pause();
SimpleTest.finish();
}
}
// Channel of visible-audio-channel-changed event should be always normal.
// Audios in background should not effect visible-audio-channel-changed.
function runFgBgTest() {
expectedAudioTypes = ["normal", "content", "notification",
"alarm", "telephony", "ringer", "publicnotification", "cmd-pause",
"ringer", "telephony", "alarm", "cmd-secondPause", "notification",
"content", "normal"];
expectedVisibleAudioType = "normal";
index = 0;
script.addMessageListener('chrome-event', fgBgTestListener);
// To play a audio with normal channel in the foreground.
normalAudio = new Audio();
playWithAudioType(normalAudio, 'normal');
iframe1.src = 'file_audio.html#bg';
document.body.appendChild(iframe1);
iframe1.setVisible(false);
}
function bgTestListener(message) {
var type = message.type;
var channel = message.channel;
if (type == 'audio-channel-changed') {
is(channel, expectedAudioTypes[index], channel + " is received and expected " + expectedAudioTypes[index]);
index++;
}
if (type == 'visible-audio-channel-changed') {
is(channel, expectedVisibleAudioType, channel + " is received and expected " + expectedVisibleAudioType);
}
// All audio types are playing now so ask to pause them.
if ('cmd-pause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudio';
index++;
}
if ('cmd-secondPause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudioFollowing';
index++;
}
if (index == expectedAudioTypes.length) {
document.body.removeChild(iframe1);
script.removeMessageListener('chrome-event', bgTestListener);
runFgBgTest();
}
}
// 1. Channel of visible-audio-channel-changed event should be always none.
// 2. normal is not allowed to be played in the background.
function runBgTest() {
expectedAudioTypes = ["content", "notification",
"alarm", "telephony", "ringer", "publicnotification", "cmd-pause",
"ringer", "telephony", "alarm", "cmd-secondPause", "notification",
"content", "none"];
expectedVisibleAudioType = "none";
index = 0;
script.addMessageListener('chrome-event', bgTestListener);
iframe1.src = 'file_audio.html#bg';
document.body.appendChild(iframe1);
iframe1.setVisible(false);
}
function fgTestListener(message) {
var type = message.type;
var channel = message.channel;
if (type == 'audio-channel-changed') {
is(channel, expectedAudioTypes[index], channel + " is received and expected " + expectedAudioTypes[index]);
index++;
}
if (type == 'visible-audio-channel-changed') {
is(channel, expectedAudioTypes[visibleIndex], channel + " is received and expected " + expectedAudioTypes[visibleIndex]);
visibleIndex++;
}
// All audio types are playing now so ask to pause them.
if ('cmd-pause' == expectedAudioTypes[visibleIndex] &&
'cmd-pause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudio';
visibleIndex++;
index++;
}
if ('cmd-secondPause' == expectedAudioTypes[visibleIndex] &&
'cmd-secondPause' == expectedAudioTypes[index]) {
iframe1.src = 'file_audio.html#pauseAudioFollowing';
visibleIndex++;
index++;
}
if (index == expectedAudioTypes.length && visibleIndex == expectedAudioTypes.length) {
document.body.removeChild(iframe1);
script.removeMessageListener('chrome-event', fgTestListener);
runBgTest();
}
}
// The foreground audio will effect both of audio-channel-changed and
// visible-audio-channel-changed.
function runFgTest() {
expectedAudioTypes = ["normal", "content", "notification",
"alarm", "telephony", "ringer", "publicnotification",
"cmd-pause", "ringer", "telephony", "alarm",
"cmd-secondPause", "notification", "content",
"normal", "none"];
index = 0;
visibleIndex = 0;
script.addMessageListener('chrome-event', fgTestListener);
iframe1 = document.createElement('iframe');
iframe1.setAttribute('mozbrowser', true);
iframe1.src = 'file_audio.html#fg';
document.body.appendChild(iframe1);
}
var url = SimpleTest.getTestFileURL("AudioChannelChromeScript.js")
var script = SpecialPowers.loadChromeScript(url);
script.sendAsyncMessage("init-chrome-event", {
type: 'audio-channel-changed'
});
script.sendAsyncMessage("init-chrome-event", {
type: 'visible-audio-channel-changed'
});
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], function() {
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.browser_frames.oop_by_default", true],
["media.useAudioChannelService", true],
["dom.mozBrowserFramesEnabled", true]]}, runFgTest);
});
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,87 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test the Telephony Channel Policy</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
function mainApp() {
var audio = new Audio();
audio.mozAudioChannelType = 'telephony';
audio.src = "audio.ogg";
audio.loop = true;
audio.play();
audio.addEventListener('mozinterruptbegin', function() {
ok(true, "This element has been muted!");
}, false);
audio.addEventListener('mozinterruptend', function() {
ok(true, "This element has been unmuted!");
audio.pause();
runTest();
}, false);
setTimeout(runTest, 600);
}
function newApp() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', true);
// That needs to be an app.
iframe.setAttribute('mozapp', 'https://acertified.com/manifest.webapp');
iframe.src = "file_telephonyPolicy.html";
document.body.appendChild(iframe);
}
var tests = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document },
{ "type": "audio-channel-telephony", "allow": 1, "context": document }], runTest);
},
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.browser_frames.oop_by_default", true],
["media.useAudioChannelAPI", true],
["media.useAudioChannelService", true],
["media.defaultAudioChannel", "telephony"],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true]]}, runTest);
},
// Run 2 apps
mainApp,
newApp,
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
function finish() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
runTest();
</script>
</body>
</html>

Просмотреть файл

@ -2055,7 +2055,6 @@ GK_ATOM(onwarning, "onwarning")
GK_ATOM(onstart, "onstart")
GK_ATOM(onstop, "onstop")
GK_ATOM(onphoto, "onphoto")
GK_ATOM(onactivestatechanged, "onactivestatechanged")
#ifdef MOZ_GAMEPAD
GK_ATOM(ongamepadbuttondown, "ongamepadbuttondown")
GK_ATOM(ongamepadbuttonup, "ongamepadbuttonup")

Просмотреть файл

@ -3735,10 +3735,39 @@ nsPIDOMWindow::SetAudioVolume(float aVolume)
return NS_OK;
}
float
nsPIDOMWindow::GetAudioGlobalVolume()
{
float globalVolume = 1.0;
nsCOMPtr<nsPIDOMWindow> window = this;
do {
if (window->GetAudioMuted()) {
return 0;
}
globalVolume *= window->GetAudioVolume();
nsCOMPtr<nsIDOMWindow> win;
window->GetParent(getter_AddRefs(win));
if (window == win) {
break;
}
window = do_QueryInterface(win);
// If there is not parent, or we are the toplevel or the volume is
// already 0.0, we don't continue.
} while (window && window != this && globalVolume);
return globalVolume;
}
void
nsPIDOMWindow::RefreshMediaElements()
{
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
service->RefreshAgentsVolume(GetCurrentInnerWindow());
}

Просмотреть файл

@ -185,6 +185,8 @@ public:
float GetAudioVolume() const;
nsresult SetAudioVolume(float aVolume);
float GetAudioGlobalVolume();
virtual void SetServiceWorkersTestingEnabled(bool aEnabled)
{
MOZ_ASSERT(IsOuterWindow());

Просмотреть файл

@ -1,489 +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 "BrowserElementAudioChannel.h"
#include "mozilla/Services.h"
#include "mozilla/dom/BrowserElementAudioChannelBinding.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/ToJSValue.h"
#include "AudioChannelService.h"
#include "nsIBrowserElementAPI.h"
#include "nsIDocShell.h"
#include "nsIDOMDOMRequest.h"
#include "nsIObserverService.h"
#include "nsISupportsPrimitives.h"
#include "nsITabParent.h"
#include "nsPIDOMWindow.h"
namespace {
void
AssertIsInMainProcess()
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
}
} // anonymous namespace
namespace mozilla {
namespace dom {
NS_IMPL_ADDREF_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BrowserElementAudioChannel, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BrowserElementAudioChannel)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_INHERITED(BrowserElementAudioChannel,
DOMEventTargetHelper,
mFrameLoader,
mFrameWindow,
mTabParent,
mBrowserElementAPI)
BrowserElementAudioChannel::BrowserElementAudioChannel(
nsPIDOMWindow* aWindow,
nsIFrameLoader* aFrameLoader,
nsIBrowserElementAPI* aAPI,
AudioChannel aAudioChannel)
: DOMEventTargetHelper(aWindow)
, mFrameLoader(aFrameLoader)
, mBrowserElementAPI(aAPI)
, mAudioChannel(aAudioChannel)
, mState(eStateUnknown)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
MOZ_ASSERT(mFrameLoader);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
nsAutoString name;
AudioChannelService::GetAudioChannelString(aAudioChannel, name);
nsAutoCString topic;
topic.Assign("audiochannel-activity-");
topic.Append(NS_ConvertUTF16toUTF8(name));
obs->AddObserver(this, topic.get(), true);
}
}
BrowserElementAudioChannel::~BrowserElementAudioChannel()
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
nsAutoString name;
AudioChannelService::GetAudioChannelString(mAudioChannel, name);
nsAutoCString topic;
topic.Assign("audiochannel-activity-");
topic.Append(NS_ConvertUTF16toUTF8(name));
obs->RemoveObserver(this, topic.get());
}
}
nsresult
BrowserElementAudioChannel::Initialize()
{
nsCOMPtr<nsIDocShell> docShell;
nsresult rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (docShell) {
nsCOMPtr<nsPIDOMWindow> window = docShell->GetWindow();
if (!window) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMWindow> topWindow;
window->GetScriptableTop(getter_AddRefs(topWindow));
mFrameWindow = do_QueryInterface(topWindow);
mFrameWindow = mFrameWindow->GetOuterWindow();
return NS_OK;
}
rv = mFrameLoader->GetTabParent(getter_AddRefs(mTabParent));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(mTabParent);
return NS_OK;
}
JSObject*
BrowserElementAudioChannel::WrapObject(JSContext *aCx,
JS::Handle<JSObject*> aGivenProto)
{
return BrowserElementAudioChannelBinding::Wrap(aCx, this, aGivenProto);
}
AudioChannel
BrowserElementAudioChannel::Name() const
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
return mAudioChannel;
}
namespace {
class BaseRunnable : public nsRunnable
{
protected:
nsCOMPtr<nsPIDOMWindow> mParentWindow;
nsCOMPtr<nsPIDOMWindow> mFrameWindow;
nsRefPtr<DOMRequest> mRequest;
AudioChannel mAudioChannel;
virtual void DoWork(AudioChannelService* aService,
JSContext* aCx) = 0;
public:
BaseRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel)
: mParentWindow(aParentWindow)
, mFrameWindow(aFrameWindow)
, mRequest(aRequest)
, mAudioChannel(aAudioChannel)
{}
NS_IMETHODIMP Run() override
{
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
MOZ_ASSERT(service);
AutoJSAPI jsapi;
if (!jsapi.Init(mParentWindow)) {
mRequest->FireError(NS_ERROR_FAILURE);
return NS_OK;
}
DoWork(service, jsapi.cx());
return NS_OK;
}
};
class GetVolumeRunnable final : public BaseRunnable
{
public:
GetVolumeRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel)
: BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
{}
protected:
virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
{
float volume = aService->GetAudioChannelVolume(mFrameWindow, mAudioChannel);
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, volume, &value)) {
mRequest->FireError(NS_ERROR_FAILURE);
return;
}
mRequest->FireSuccess(value);
}
};
class GetMutedRunnable final : public BaseRunnable
{
public:
GetMutedRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel)
: BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
{}
protected:
virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
{
bool muted = aService->GetAudioChannelMuted(mFrameWindow, mAudioChannel);
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, muted, &value)) {
mRequest->FireError(NS_ERROR_FAILURE);
return;
}
mRequest->FireSuccess(value);
}
};
class IsActiveRunnable final : public BaseRunnable
{
bool mActive;
bool mValueKnown;
public:
IsActiveRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel,
bool aActive)
: BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
, mActive(aActive)
, mValueKnown(true)
{}
IsActiveRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel)
: BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
, mActive(true)
, mValueKnown(false)
{}
protected:
virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
{
if (!mValueKnown) {
mActive = aService->IsAudioChannelActive(mFrameWindow, mAudioChannel);
}
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, mActive, &value)) {
mRequest->FireError(NS_ERROR_FAILURE);
return;
}
mRequest->FireSuccess(value);
}
};
class FireSuccessRunnable final : public BaseRunnable
{
public:
FireSuccessRunnable(nsPIDOMWindow* aParentWindow, nsPIDOMWindow* aFrameWindow,
DOMRequest* aRequest, AudioChannel aAudioChannel)
: BaseRunnable(aParentWindow, aFrameWindow, aRequest, aAudioChannel)
{}
protected:
virtual void DoWork(AudioChannelService* aService, JSContext* aCx) override
{
JS::Rooted<JS::Value> value(aCx);
mRequest->FireSuccess(value);
}
};
} // anonymous namespace
already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::GetVolume(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
aRv = mBrowserElementAPI->GetAudioChannelVolume((uint32_t)mAudioChannel,
getter_AddRefs(request));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable =
new GetVolumeRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::SetVolume(float aVolume, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
aRv = mBrowserElementAPI->SetAudioChannelVolume((uint32_t)mAudioChannel,
aVolume,
getter_AddRefs(request));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
MOZ_ASSERT(service);
service->SetAudioChannelVolume(mFrameWindow, mAudioChannel, aVolume);
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable = new FireSuccessRunnable(GetOwner(),
mFrameWindow,
domRequest,
mAudioChannel);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::GetMuted(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
aRv = mBrowserElementAPI->GetAudioChannelMuted((uint32_t)mAudioChannel,
getter_AddRefs(request));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable =
new GetMutedRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::SetMuted(bool aMuted, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
aRv = mBrowserElementAPI->SetAudioChannelMuted((uint32_t)mAudioChannel,
aMuted,
getter_AddRefs(request));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
MOZ_ASSERT(service);
service->SetAudioChannelMuted(mFrameWindow, mAudioChannel, aMuted);
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable = new FireSuccessRunnable(GetOwner(),
mFrameWindow,
domRequest,
mAudioChannel);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::IsActive(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (mState != eStateUnknown) {
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable =
new IsActiveRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel,
mState == eStateActive);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
aRv = mBrowserElementAPI->IsAudioChannelActive((uint32_t)mAudioChannel,
getter_AddRefs(request));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return request.forget().downcast<DOMRequest>();
}
nsRefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
nsCOMPtr<nsIRunnable> runnable =
new IsActiveRunnable(GetOwner(), mFrameWindow, domRequest, mAudioChannel);
NS_DispatchToMainThread(runnable);
return domRequest.forget();
}
NS_IMETHODIMP
BrowserElementAudioChannel::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
nsAutoString name;
AudioChannelService::GetAudioChannelString(mAudioChannel, name);
nsAutoCString topic;
topic.Assign("audiochannel-activity-");
topic.Append(NS_ConvertUTF16toUTF8(name));
if (strcmp(topic.get(), aTopic)) {
return NS_OK;
}
// Message received from the child.
if (!mFrameWindow) {
if (mTabParent == aSubject) {
ProcessStateChanged(aData);
}
return NS_OK;
}
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
if (NS_WARN_IF(!wrapper)) {
return NS_ERROR_FAILURE;
}
uint64_t windowID;
nsresult rv = wrapper->GetData(&windowID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (windowID != mFrameWindow->WindowID()) {
return NS_OK;
}
ProcessStateChanged(aData);
return NS_OK;
}
void
BrowserElementAudioChannel::ProcessStateChanged(const char16_t* aData)
{
nsAutoString value(aData);
mState = value.EqualsASCII("active") ? eStateActive : eStateInactive;
DispatchTrustedEvent(NS_LITERAL_STRING("activestatechanged"));
}
} // dom namespace
} // mozilla namespace

Просмотреть файл

@ -1,83 +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/. */
#ifndef mozilla_dom_BrowserElementAudioChannels_h
#define mozilla_dom_BrowserElementAudioChannels_h
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIObserver.h"
#include "nsIFrameLoader.h"
#include "nsWeakReference.h"
#include "nsWrapperCache.h"
class nsIBrowserElementAPI;
class nsITabParent;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class DOMRequest;
class BrowserElementAudioChannel final : public DOMEventTargetHelper
, public nsSupportsWeakReference
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIOBSERVER
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BrowserElementAudioChannel,
DOMEventTargetHelper)
BrowserElementAudioChannel(nsPIDOMWindow* aWindow,
nsIFrameLoader* aFrameLoader,
nsIBrowserElementAPI* aAPI,
AudioChannel aAudioChannel);
nsresult Initialize();
// WebIDL methods
virtual JSObject* WrapObject(JSContext *aCx,
JS::Handle<JSObject*> aGivenProto) override;
AudioChannel Name() const;
already_AddRefed<dom::DOMRequest> GetVolume(ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> SetVolume(float aVolume, ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> GetMuted(ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> SetMuted(bool aMuted, ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> IsActive(ErrorResult& aRv);
IMPL_EVENT_HANDLER(activestatechanged);
private:
~BrowserElementAudioChannel();
void ProcessStateChanged(const char16_t* aData);
nsCOMPtr<nsIFrameLoader> mFrameLoader;
nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
nsCOMPtr<nsITabParent> mTabParent;
nsCOMPtr<nsPIDOMWindow> mFrameWindow;
AudioChannel mAudioChannel;
enum {
eStateActive,
eStateInactive,
eStateUnknown
} mState;
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_BrowserElementAudioChannels_h

Просмотреть файл

@ -13,10 +13,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "acs",
"@mozilla.org/audiochannel/service;1",
"nsIAudioChannelService");
let kLongestReturnedString = 128;
function debug(msg) {
@ -238,11 +234,6 @@ BrowserElementChild.prototype = {
"find-all": this._recvFindAll.bind(this),
"find-next": this._recvFindNext.bind(this),
"clear-match": this._recvClearMatch.bind(this),
"get-audio-channel-volume": this._recvGetAudioChannelVolume,
"set-audio-channel-volume": this._recvSetAudioChannelVolume,
"get-audio-channel-muted": this._recvGetAudioChannelMuted,
"set-audio-channel-muted": this._recvSetAudioChannelMuted,
"get-is-audio-channel-active": this._recvIsAudioChannelActive
}
addMessageListener("browser-element-api:call", function(aMessage) {
@ -1255,55 +1246,6 @@ BrowserElementChild.prototype = {
}
},
_recvGetAudioChannelVolume: function(data) {
debug("Received getAudioChannelVolume message: (" + data.json.id + ")");
let volume = acs.getAudioChannelVolume(content,
data.json.args.audioChannel);
sendAsyncMsg('got-audio-channel-volume', {
id: data.json.id, successRv: volume
});
},
_recvSetAudioChannelVolume: function(data) {
debug("Received setAudioChannelVolume message: (" + data.json.id + ")");
acs.setAudioChannelVolume(content,
data.json.args.audioChannel,
data.json.args.volume);
sendAsyncMsg('got-set-audio-channel-volume', {
id: data.json.id, successRv: true
});
},
_recvGetAudioChannelMuted: function(data) {
debug("Received getAudioChannelMuted message: (" + data.json.id + ")");
let muted = acs.getAudioChannelMuted(content, data.json.args.audioChannel);
sendAsyncMsg('got-audio-channel-muted', {
id: data.json.id, successRv: muted
});
},
_recvSetAudioChannelMuted: function(data) {
debug("Received setAudioChannelMuted message: (" + data.json.id + ")");
acs.setAudioChannelMuted(content, data.json.args.audioChannel,
data.json.args.muted);
sendAsyncMsg('got-set-audio-channel-muted', {
id: data.json.id, successRv: true
});
},
_recvIsAudioChannelActive: function(data) {
debug("Received isAudioChannelActive message: (" + data.json.id + ")");
let active = acs.isAudioChannelActive(content, data.json.args.audioChannel);
sendAsyncMsg('got-is-audio-channel-active', {
id: data.json.id, successRv: active
});
},
_initFinder: function() {
if (!this._finder) {
try {

Просмотреть файл

@ -15,7 +15,6 @@
#endif
#include "BrowserElementParent.h"
#include "BrowserElementAudioChannel.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/ToJSValue.h"

Просмотреть файл

@ -206,12 +206,7 @@ BrowserElementParent.prototype = {
"selectionstatechanged": this._handleSelectionStateChanged,
"scrollviewchange": this._handleScrollViewChange,
"caretstatechanged": this._handleCaretStateChanged,
"findchange": this._handleFindChange,
"got-audio-channel-volume": this._gotDOMRequestResult,
"got-set-audio-channel-volume": this._gotDOMRequestResult,
"got-audio-channel-muted": this._gotDOMRequestResult,
"got-set-audio-channel-muted": this._gotDOMRequestResult,
"got-is-audio-channel-active": this._gotDOMRequestResult
"findchange": this._handleFindChange
};
let mmSecuritySensitiveCalls = {
@ -978,33 +973,6 @@ BrowserElementParent.prototype = {
}
},
getAudioChannelVolume: function(aAudioChannel) {
return this._sendDOMRequest('get-audio-channel-volume',
{audioChannel: aAudioChannel});
},
setAudioChannelVolume: function(aAudioChannel, aVolume) {
return this._sendDOMRequest('set-audio-channel-volume',
{audioChannel: aAudioChannel,
volume: aVolume});
},
getAudioChannelMuted: function(aAudioChannel) {
return this._sendDOMRequest('get-audio-channel-muted',
{audioChannel: aAudioChannel});
},
setAudioChannelMuted: function(aAudioChannel, aMuted) {
return this._sendDOMRequest('set-audio-channel-muted',
{audioChannel: aAudioChannel,
muted: aMuted});
},
isAudioChannelActive: function(aAudioChannel) {
return this._sendDOMRequest('get-is-audio-channel-active',
{audioChannel: aAudioChannel});
},
/**
* Called when the visibility of the window which owns this iframe changes.
*/

Просмотреть файл

@ -1,153 +0,0 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 1113086 - tests for AudioChannel API into BrowserElement
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
SpecialPowers.setBoolPref("dom.testing.browserElementAudioChannel.noapp", true);
SpecialPowers.setBoolPref("media.useAudioChannelService", true);
function noaudio() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_empty.html';
function noaudio_loadend() {
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
var ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getVolume" in ac, "ac.getVolume exists");
ok("setVolume" in ac, "ac.setVolume exists");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ok("isActive" in ac, "ac.isActive exists");
new Promise(function(r, rr) {
var req = ac.getVolume();
ok(req instanceof DOMRequest, "This is a domRequest.");
req.onsuccess = function(e) {
is(e.target.result, 1.0, "The default volume should be 1.0");
r();
}
})
.then(function() {
return new Promise(function(r, rr) {
ac.getMuted().onsuccess = function(e) {
is(e.target.result, false, "The default muted value should be false");
r();
}
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.setVolume(0.8).onsuccess = function() { r(); }
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.getVolume().onsuccess = function(e) {
// the actual value is 0.800000011920929..
ok(Math.abs(0.8 - e.target.result) < 0.01, "The new volume should be 0.8: " + e.target.result);
r();
}
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.setVolume(1.0).onsuccess = function() { r(); }
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.setMuted(true).onsuccess = function() { r(); }
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.getMuted().onsuccess = function(e) {
is(e.target.result, true, "The new muted value should be true");
r();
}
});
})
.then(function() {
return new Promise(function(r, rr) {
ac.isActive().onsuccess = function(e) {
is(e.target.result, false, "ac.isActive is false: no audio element active.");
r();
}
});
})
.then(runTests);
}
iframe.addEventListener('mozbrowserloadend', noaudio_loadend);
document.body.appendChild(iframe);
}
function audio() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/iframe_file_audio.html';
function audio_loadend() {
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
var ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getVolume" in ac, "ac.getVolume exists");
ok("setVolume" in ac, "ac.setVolume exists");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ok("isActive" in ac, "ac.isActive exists");
ac.onactivestatechanged = function() {
ok("activestatechanged event received.");
ac.onactivestatechanged = null;
runTests();
}
}
iframe.addEventListener('mozbrowserloadend', audio_loadend);
document.body.appendChild(iframe);
}
var tests = [ noaudio, audio ];
function runTests() {
if (tests.length == 0) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
addEventListener('load', function() {
SimpleTest.executeSoon(runTests);
});

Просмотреть файл

@ -1,15 +0,0 @@
<html>
<body>
<audio src="http://mochi.test:8888/tests/dom/browser-element/mochitest/audio.ogg" id="audio" />
<script>
var audio = document.getElementById('audio');
audio.play();
audio.onended = function() {
setTimeout(function() {
audio.play();
}, 0);
}
</script>
</body>
</html>

Просмотреть файл

@ -1,5 +0,0 @@
<html>
<body>
<iframe src="file_audio.html"></iframe>
</body>
</html>

Просмотреть файл

@ -109,4 +109,3 @@ disabled = bug 924771
[test_browserElement_oop_ExposableURI.html]
disabled = bug 924771
[test_browserElement_oop_GetContentDimensions.html]
[test_browserElement_oop_AudioChannel.html]

Просмотреть файл

@ -75,7 +75,6 @@ support-files =
browserElement_XFrameOptionsSameOrigin.js
browserElement_XFrameOptionsSameOrigin.js
browserElement_GetContentDimensions.js
browserElement_AudioChannel.js
file_browserElement_AlertInFrame.html
file_browserElement_AlertInFrame_Inner.html
file_browserElement_AllowEmbedAppsInNestedOOIframe.html
@ -123,8 +122,6 @@ support-files =
file_inputmethod.html
file_post_request.html
file_wyciwyg.html
file_audio.html
iframe_file_audio.html
# Note: browserElementTestHelpers.js looks at the test's filename to determine
# whether the test should be OOP. "_oop_" signals OOP, "_inproc_" signals in
@ -226,4 +223,3 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
[test_browserElement_inproc_Reload.html]
disabled = bug 774100
[test_browserElement_inproc_GetContentDimensions.html]
[test_browserElement_inproc_AudioChannel.html]

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test of browser element audioChannel.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel.js">
</script>
</body>
</html>

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test of browser element audioChannel.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel.js">
</script>
</body>
</html>

Просмотреть файл

@ -8,12 +8,7 @@ EXPORTS.mozilla += [
'BrowserElementParent.h',
]
EXPORTS.mozilla.dom += [
'BrowserElementAudioChannel.h',
]
SOURCES += [
'BrowserElementAudioChannel.cpp',
'BrowserElementParent.cpp',
]

Просмотреть файл

@ -26,7 +26,7 @@ interface nsIBrowserElementNextPaintListener : nsISupports
* Interface to the BrowserElementParent implementation. All methods
* but setFrameLoader throw when the remote process is dead.
*/
[scriptable, uuid(daa264b2-54df-4fc7-89b7-c9d02167c5d4)]
[scriptable, uuid(8ecb598c-f886-11e4-9915-778f934fbf93)]
interface nsIBrowserElementAPI : nsISupports
{
const long FIND_CASE_SENSITIVE = 0;
@ -82,13 +82,5 @@ interface nsIBrowserElementAPI : nsISupports
nsIDOMDOMRequest setInputMethodActive(in boolean isActive);
nsIDOMDOMRequest getAudioChannelVolume(in uint32_t audioChannel);
nsIDOMDOMRequest setAudioChannelVolume(in uint32_t audioChannel, in float volume);
nsIDOMDOMRequest getAudioChannelMuted(in uint32_t audioChannel);
nsIDOMDOMRequest setAudioChannelMuted(in uint32_t audioChannel, in bool muted);
nsIDOMDOMRequest isAudioChannelActive(in uint32_t audioChannel);
void setNFCFocus(in boolean isFocus);
};

Просмотреть файл

@ -1135,12 +1135,8 @@ nsDOMCameraControl::NotifyRecordingStatusChange(const nsString& aMsg)
// Camera app will stop recording when it falls to the background, so no callback is necessary.
mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
// Video recording doesn't output any sound, so it's not necessary to check canPlay.
float volume = 0.0;
bool muted = true;
rv = mAudioChannelAgent->StartPlaying(&volume, &muted);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
int32_t canPlay;
mAudioChannelAgent->StartPlaying(&canPlay);
}
#endif
return rv;

Просмотреть файл

@ -135,6 +135,13 @@ FMRadio::Init(nsPIDOMWindow *aWindow)
RegisterSwitchObserver(SWITCH_HEADPHONES, this);
}
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
// All of the codes below are for AudioChannel. We can directly return here
// if preferences doesn't enable AudioChannelService.
NS_ENSURE_TRUE_VOID(Preferences::GetBool("media.useAudioChannelService"));
@ -148,6 +155,13 @@ FMRadio::Init(nsPIDOMWindow *aWindow)
nsIAudioChannelAgent::AUDIO_AGENT_CHANNEL_CONTENT,
this);
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
NS_ENSURE_TRUE_VOID(docshell);
bool isActive = false;
docshell->GetIsActive(&isActive);
audioChannelAgent->SetVisibilityState(isActive);
// Once all necessary resources are got successfully, we just enabled
// mAudioChannelAgent.
mAudioChannelAgent = audioChannelAgent;
@ -162,6 +176,11 @@ FMRadio::Shutdown()
UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
}
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
/* useCapture = */ true);
mIsShutdown = true;
}
@ -450,30 +469,61 @@ FMRadio::DisableRDS()
return r.forget();
}
NS_IMETHODIMP
FMRadio::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString type;
aEvent->GetType(type);
if (!type.EqualsLiteral("visibilitychange")) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
bool isActive = false;
docshell->GetIsActive(&isActive);
mAudioChannelAgent->SetVisibilityState(isActive);
return NS_OK;
}
void
FMRadio::EnableAudioChannelAgent()
{
NS_ENSURE_TRUE_VOID(mAudioChannelAgent);
float volume = 0.0;
bool muted = true;
mAudioChannelAgent->StartPlaying(&volume, &muted);
WindowVolumeChanged(volume, muted);
int32_t playingState = 0;
mAudioChannelAgent->StartPlaying(&playingState);
SetCanPlay(playingState == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
mAudioChannelAgentEnabled = true;
}
NS_IMETHODIMP
FMRadio::WindowVolumeChanged(float aVolume, bool aMuted)
FMRadio::CanPlayChanged(int32_t aCanPlay)
{
IFMRadioService::Singleton()->EnableAudio(!aMuted);
// TODO: what about the volume?
SetCanPlay(!(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_MUTED));
return NS_OK;
}
NS_IMETHODIMP
FMRadio::WindowVolumeChanged()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
FMRadio::SetCanPlay(bool aCanPlay)
{
IFMRadioService::Singleton()->EnableAudio(aCanPlay);
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(FMRadio, DOMEventTargetHelper)

Просмотреть файл

@ -25,6 +25,7 @@ class FMRadio final : public DOMEventTargetHelper
, public FMRadioEventObserver
, public nsSupportsWeakReference
, public nsIAudioChannelAgentCallback
, public nsIDOMEventListener
{
friend class FMRadioRequest;
@ -108,9 +109,13 @@ public:
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;

Просмотреть файл

@ -14,6 +14,7 @@
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "AudioSampleFormat.h"
#include "AudioChannelCommon.h"
#include <algorithm>
#include "nsComponentManagerUtils.h"
#include "nsIHttpChannel.h"

Просмотреть файл

@ -1831,7 +1831,16 @@ void HTMLMediaElement::SetMutedInternal(uint32_t aMuted)
void HTMLMediaElement::SetVolumeInternal()
{
float effectiveVolume = mMuted ? 0.0f : float(mVolume * mAudioChannelVolume);
float effectiveVolume = mMuted ? 0.0f :
mAudioChannelFaded ? float(mVolume) * FADED_VOLUME_RATIO : float(mVolume);
if (mAudioChannelAgent) {
float volume;
nsresult rv = mAudioChannelAgent->GetWindowVolume(&volume);
if (NS_SUCCEEDED(rv)) {
effectiveVolume *= volume;
}
}
if (mDecoder) {
mDecoder->SetVolume(effectiveVolume);
@ -2083,7 +2092,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mCORSMode(CORS_NONE),
mIsEncrypted(false),
mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
mAudioChannelVolume(1.0),
mAudioChannelFaded(false),
mPlayingThroughTheAudioChannel(false),
mDisableVideo(false),
mPlayBlockedBecauseHidden(false),
@ -4034,6 +4043,13 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
mDecoder->NotifyOwnerActivityChanged();
}
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
// CanPlayChanged callback.
if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
mAudioChannelAgent) {
AutoNoJSAPI nojsapi;
mAudioChannelAgent->SetVisibilityState(!ownerDoc->Hidden());
}
bool pauseElement = !IsActive() || (mMuted & MUTED_BY_AUDIO_CHANNEL);
SuspendOrResumeElement(pauseElement, !IsActive());
@ -4450,24 +4466,26 @@ ImageContainer* HTMLMediaElement::GetImageContainer()
return container ? container->GetImageContainer() : nullptr;
}
nsresult HTMLMediaElement::UpdateChannelMuteState(float aVolume, bool aMuted)
nsresult HTMLMediaElement::UpdateChannelMuteState(AudioChannelState aCanPlay)
{
if (!UseAudioChannelService()) {
return NS_OK;
}
if (mAudioChannelVolume != aVolume) {
mAudioChannelVolume = aVolume;
if ((aCanPlay == AUDIO_CHANNEL_STATE_FADED && !mAudioChannelFaded) ||
(aCanPlay != AUDIO_CHANNEL_STATE_FADED && mAudioChannelFaded)) {
mAudioChannelFaded = !mAudioChannelFaded;
SetVolumeInternal();
}
// We have to mute this channel.
if (aMuted && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
if (aCanPlay == AUDIO_CHANNEL_STATE_MUTED && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
}
} else if (!aMuted && (mMuted & MUTED_BY_AUDIO_CHANNEL)) {
} else if (aCanPlay != AUDIO_CHANNEL_STATE_MUTED &&
(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
@ -4505,9 +4523,17 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
if (!mAudioChannelAgent) {
return;
}
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(),
static_cast<int32_t>(mAudioChannel),
this);
// Use a weak ref so the audio channel agent can't leak |this|.
if (AudioChannel::Normal == mAudioChannel && IsVideo()) {
mAudioChannelAgent->InitWithVideo(OwnerDoc()->GetWindow(),
static_cast<int32_t>(mAudioChannel),
this, true);
} else {
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(),
static_cast<int32_t>(mAudioChannel),
this);
}
mAudioChannelAgent->SetVisibilityState(!OwnerDoc()->Hidden());
}
// This is needed to pass nsContentUtils::IsCallerChrome().
@ -4516,10 +4542,9 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
AutoNoJSAPI nojsapi;
if (mPlayingThroughTheAudioChannel) {
float volume = 0.0;
bool muted = true;
mAudioChannelAgent->StartPlaying(&volume, &muted);
WindowVolumeChanged(volume, muted);
int32_t canPlay;
mAudioChannelAgent->StartPlaying(&canPlay);
CanPlayChanged(canPlay);
} else {
mAudioChannelAgent->StopPlaying();
mAudioChannelAgent = nullptr;
@ -4527,12 +4552,25 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
}
}
NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted)
/* void canPlayChanged (in boolean canPlay); */
NS_IMETHODIMP HTMLMediaElement::CanPlayChanged(int32_t canPlay)
{
static_assert(static_cast<AudioChannelState>(
nsIAudioChannelAgent::AUDIO_AGENT_STATE_NORMAL) ==
AUDIO_CHANNEL_STATE_NORMAL &&
static_cast<AudioChannelState>(
nsIAudioChannelAgent::AUDIO_AGENT_STATE_MUTED) ==
AUDIO_CHANNEL_STATE_MUTED &&
static_cast<AudioChannelState>(
nsIAudioChannelAgent::AUDIO_AGENT_STATE_FADED) ==
AUDIO_CHANNEL_STATE_FADED,
"Enum of channel state on nsIAudioChannelAgent.idl should be "
"the same with AudioChannelCommon.h");
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
UpdateChannelMuteState(aVolume, aMuted);
mPaused.SetCanPlay(!aMuted);
UpdateChannelMuteState(static_cast<AudioChannelState>(canPlay));
mPaused.SetCanPlay(canPlay != AUDIO_CHANNEL_STATE_MUTED);
return NS_OK;
}
@ -4677,6 +4715,12 @@ HTMLMediaElement::GetTopLevelPrincipal()
}
#endif // MOZ_EME
NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged()
{
SetVolumeInternal();
return NS_OK;
}
AudioTrackList*
HTMLMediaElement::AudioTracks()
{

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsIObserver.h"
#include "mozilla/CORSMode.h"
#include "DOMMediaStream.h"
#include "AudioChannelCommon.h"
#include "DecoderTraits.h"
#include "nsIAudioChannelAgent.h"
#include "mozilla/Attributes.h"
@ -1007,8 +1008,8 @@ protected:
// Check the permissions for audiochannel.
bool CheckAudioChannelPermissions(const nsAString& aType);
// This method does the check for muting/nmuting the audio channel.
nsresult UpdateChannelMuteState(float aVolume, bool aMuted);
// This method does the check for muting/fading/unmuting the audio channel.
nsresult UpdateChannelMuteState(mozilla::dom::AudioChannelState aCanPlay);
// Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the
// seek target, or PrevSyncPoint if a quicker but less precise seek is
@ -1362,8 +1363,8 @@ protected:
// Audio Channel.
AudioChannel mAudioChannel;
// The audio channel volume
float mAudioChannelVolume;
// The audio channel has been faded.
bool mAudioChannelFaded;
// Is this media element playing?
bool mPlayingThroughTheAudioChannel;

Просмотреть файл

@ -9,21 +9,15 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/dom/BrowserElementBinding.h"
#include "mozilla/dom/BrowserElementAudioChannel.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ToJSValue.h"
#include "AudioChannelService.h"
#include "mozIApplication.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsFrameLoader.h"
#include "nsIAppsService.h"
#include "nsIDOMDOMRequest.h"
#include "nsIDOMElement.h"
#include "nsIMozBrowserFrame.h"
#include "nsINode.h"
#include "nsIPrincipal.h"
@ -513,141 +507,6 @@ nsBrowserElement::SetInputMethodActive(bool aIsActive,
return req.forget().downcast<DOMRequest>();
}
void
nsBrowserElement::GetAllowedAudioChannels(
nsTArray<nsRefPtr<BrowserElementAudioChannel>>& aAudioChannels,
ErrorResult& aRv)
{
aAudioChannels.Clear();
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
// If empty, it means that this is the first call of this method.
if (mBrowserElementAudioChannels.IsEmpty()) {
nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIDOMElement> frameElement;
aRv = frameLoader->GetOwnerElement(getter_AddRefs(frameElement));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(frameElement);
nsCOMPtr<nsIDOMDocument> doc;
aRv = frameElement->GetOwnerDocument(getter_AddRefs(doc));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(doc);
nsCOMPtr<nsIDOMWindow> win;
aRv = doc->GetDefaultView(getter_AddRefs(win));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(win);
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(win);
if (!window->IsInnerWindow()) {
window = window->GetCurrentInnerWindow();
}
nsCOMPtr<nsIMozBrowserFrame> mozBrowserFrame =
do_QueryInterface(frameElement);
if (NS_WARN_IF(!mozBrowserFrame)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsAutoString manifestURL;
aRv = mozBrowserFrame->GetAppManifestURL(manifestURL);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsCOMPtr<nsIAppsService> appsService =
do_GetService("@mozilla.org/AppsService;1");
if (NS_WARN_IF(!appsService)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<mozIApplication> app;
aRv = appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
bool noapp = false;
Preferences::GetBool("dom.testing.browserElementAudioChannel.noapp", &noapp);
if (!noapp && !app) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
// Normal is always allowed.
nsTArray<nsRefPtr<BrowserElementAudioChannel>> channels;
nsRefPtr<BrowserElementAudioChannel> ac =
new BrowserElementAudioChannel(window, frameLoader, mBrowserElementAPI,
AudioChannel::Normal);
aRv = ac->Initialize();
if (NS_WARN_IF(aRv.Failed())) {
return;
}
channels.AppendElement(ac);
// app can be null in case we are in a test.
if (app) {
const nsAttrValue::EnumTable* audioChannelTable =
AudioChannelService::GetAudioChannelTable();
bool allowed;
nsAutoCString permissionName;
for (uint32_t i = 0; audioChannelTable && audioChannelTable[i].tag; ++i) {
permissionName.AssignASCII("audio-channel-");
permissionName.AppendASCII(audioChannelTable[i].tag);
aRv = app->HasPermission(permissionName.get(), &allowed);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (allowed) {
nsRefPtr<BrowserElementAudioChannel> ac =
new BrowserElementAudioChannel(window, frameLoader,
mBrowserElementAPI,
(AudioChannel)audioChannelTable[i].value);
aRv = ac->Initialize();
if (NS_WARN_IF(aRv.Failed())) {
return;
}
channels.AppendElement(ac);
}
}
}
mBrowserElementAudioChannels.AppendElements(channels);
}
aAudioChannels.AppendElements(mBrowserElementAudioChannels);
}
void
nsBrowserElement::SetNFCFocus(bool aIsFocus,
ErrorResult& aRv)

Просмотреть файл

@ -8,7 +8,6 @@
#define nsBrowserElement_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BrowserElementAudioChannel.h"
#include "nsCOMPtr.h"
#include "nsIBrowserElementAPI.h"
@ -71,10 +70,6 @@ public:
already_AddRefed<dom::DOMRequest> PurgeHistory(ErrorResult& aRv);
void GetAllowedAudioChannels(
nsTArray<nsRefPtr<dom::BrowserElementAudioChannel>>& aAudioChannels,
ErrorResult& aRv);
already_AddRefed<dom::DOMRequest>
GetScreenshot(uint32_t aWidth,
uint32_t aHeight,
@ -107,7 +102,6 @@ protected:
NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
void InitBrowserElementAPI();
nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
nsTArray<nsRefPtr<dom::BrowserElementAudioChannel>> mBrowserElementAudioChannels;
private:
bool IsBrowserElementOrThrow(ErrorResult& aRv);

Просмотреть файл

@ -6,7 +6,6 @@
#include "nsGenericHTMLFrameElement.h"
#include "mozilla/dom/BrowserElementAudioChannel.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Preferences.h"
#include "mozilla/ErrorResult.h"
@ -35,20 +34,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAudioChannels)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
if (tmp->mFrameLoader) {
tmp->mFrameLoader->Destroy();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAudioChannels)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
NS_IMPL_RELEASE_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)

Просмотреть файл

@ -71,8 +71,8 @@ public:
virtual int32_t TabIndexDefault() override;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aError);

Просмотреть файл

@ -182,6 +182,7 @@
#include "nsContentUtils.h"
#include "nsIPrincipal.h"
#include "nsDeviceStorage.h"
#include "AudioChannelService.h"
#include "DomainPolicy.h"
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/telephony/PTelephonyChild.h"
@ -942,6 +943,17 @@ NS_IMETHODIMP MemoryReportRequestChild::Run()
return sent ? NS_OK : NS_ERROR_FAILURE;
}
bool
ContentChild::RecvAudioChannelNotify()
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetAudioChannelService();
if (service) {
service->Notify();
}
return true;
}
bool
ContentChild::RecvDataStoreNotify(const uint32_t& aAppId,
const nsString& aName,

Просмотреть файл

@ -200,6 +200,9 @@ public:
const FileDescriptor& aGCLog,
const FileDescriptor& aCCLog) override;
virtual bool
RecvAudioChannelNotify() override;
virtual bool
RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName,
const nsString& aManifestURL) override;

Просмотреть файл

@ -2792,27 +2792,66 @@ ContentParent::RecvFirstIdle()
}
bool
ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden)
ContentParent::RecvAudioChannelGetState(const AudioChannel& aChannel,
const bool& aElementHidden,
const bool& aElementWasHidden,
AudioChannelState* aState)
{
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
*aState = AUDIO_CHANNEL_STATE_NORMAL;
MOZ_ASSERT(service);
service->SetDefaultVolumeControlChannelInternal(aChannel,
aHidden, mChildID);
*aState = service->GetStateInternal(aChannel, mChildID,
aElementHidden, aElementWasHidden);
return true;
}
bool
ContentParent::RecvAudioChannelServiceStatus(
const bool& aTelephonyChannel,
const bool& aContentOrNormalChannel,
const bool& aAnyChannel)
ContentParent::RecvAudioChannelRegisterType(const AudioChannel& aChannel,
const bool& aWithVideo)
{
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
MOZ_ASSERT(service);
service->RegisterType(aChannel, mChildID, aWithVideo);
service->ChildStatusReceived(mChildID, aTelephonyChannel,
aContentOrNormalChannel, aAnyChannel);
return true;
}
bool
ContentParent::RecvAudioChannelUnregisterType(const AudioChannel& aChannel,
const bool& aElementHidden,
const bool& aWithVideo)
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
MOZ_ASSERT(service);
service->UnregisterType(aChannel, aElementHidden, mChildID, aWithVideo);
return true;
}
bool
ContentParent::RecvAudioChannelChangedNotification()
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
MOZ_ASSERT(service);
service->SendAudioChannelChangedNotification(ChildID());
return true;
}
bool
ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden)
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetOrCreateAudioChannelService();
MOZ_ASSERT(service);
service->SetDefaultVolumeControlChannelInternal(aChannel,
aHidden, mChildID);
return true;
}

Просмотреть файл

@ -752,13 +752,21 @@ private:
virtual bool RecvFirstIdle() override;
virtual bool RecvAudioChannelGetState(const AudioChannel& aChannel,
const bool& aElementHidden,
const bool& aElementWasHidden,
AudioChannelState* aValue) override;
virtual bool RecvAudioChannelRegisterType(const AudioChannel& aChannel,
const bool& aWithVideo) override;
virtual bool RecvAudioChannelUnregisterType(const AudioChannel& aChannel,
const bool& aElementHidden,
const bool& aWithVideo) override;
virtual bool RecvAudioChannelChangedNotification() override;
virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden) override;
virtual bool RecvAudioChannelServiceStatus(const bool& aTelephonyChannel,
const bool& aContentOrNormalChannel,
const bool& aAnyChannel) override;
virtual bool RecvGetSystemMemory(const uint64_t& getterId) override;
virtual bool RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;

Просмотреть файл

@ -539,10 +539,6 @@ parent:
InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
nsCString visualData, uint32_t width, uint32_t height,
uint32_t stride, uint8_t format, int32_t dragAreaX, int32_t dragAreaY);
async AudioChannelActivityNotification(uint32_t aAudioChannel,
bool aActive);
child:
/**
* Notify the remote browser that it has been Show()n on this

Просмотреть файл

@ -81,6 +81,8 @@ using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
@ -496,6 +498,11 @@ child:
PMemoryReportRequest(uint32_t generation, bool anonymize,
bool minimizeMemoryUsage, MaybeFileDesc DMDFile);
/**
* Notify the AudioChannelService in the child processes.
*/
async AudioChannelNotify();
async SpeakerManagerNotify();
/**
@ -863,10 +870,17 @@ parent:
// Tell the parent that the child has gone idle for the first time
async FirstIdle();
async AudioChannelServiceStatus(bool aActiveTelephonyChannel,
bool aContentOrNormalChannel,
bool aAnyActiveChannel);
// Get Muted from the main AudioChannelService.
sync AudioChannelGetState(AudioChannel aChannel, bool aElementHidden,
bool aElementWasHidden)
returns (AudioChannelState value);
sync AudioChannelRegisterType(AudioChannel aChannel, bool aWithVideo);
sync AudioChannelUnregisterType(AudioChannel aChannel,
bool aElementHidden,
bool aWithVideo);
async AudioChannelChangedNotification();
async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
sync DataStoreGetStores(nsString aName, nsString aOwner, Principal aPrincipal)

Просмотреть файл

@ -1041,7 +1041,7 @@ ParticularProcessPriorityManager::ComputePriority()
return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
AudioChannelService* service = AudioChannelService::GetOrCreateAudioChannelService();
if (service->ProcessContentOrNormalChannelIsActive(ChildID())) {
return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
}

Просмотреть файл

@ -877,7 +877,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mDefaultScale(0)
, mIPCOpen(true)
, mParentIsActive(false)
, mAudioChannelActive(false)
{
// In the general case having the TabParent tell us if APZ is enabled or not
// doesn't really work because the TabParent itself may not have a reference
@ -891,22 +890,6 @@ TabChild::TabChild(nsIContentChild* aManager,
MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
NestedTabChildMap()[mUniqueId] = this;
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
const nsAttrValue::EnumTable* table =
AudioChannelService::GetAudioChannelTable();
nsAutoCString topic;
for (uint32_t i = 0; table[i].tag; ++i) {
topic.Assign("audiochannel-activity-");
topic.Append(table[i].tag);
observerService->AddObserver(this, topic.get(), false);
}
}
}
NS_IMETHODIMP
@ -974,56 +957,6 @@ TabChild::Observe(nsISupports *aSubject,
}
}
const nsAttrValue::EnumTable* table =
AudioChannelService::GetAudioChannelTable();
nsAutoCString topic;
int16_t audioChannel = -1;
for (uint32_t i = 0; table[i].tag; ++i) {
topic.Assign("audiochannel-activity-");
topic.Append(table[i].tag);
if (topic.Equals(aTopic)) {
audioChannel = table[i].value;
break;
}
}
if (audioChannel != -1 && mIPCOpen) {
// If the subject is not a wrapper, it is sent by the TabParent and we
// should ignore it.
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
if (!wrapper) {
return NS_OK;
}
// We must have a window in order to compare the windowID contained into the
// wrapper.
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
if (!window) {
return NS_OK;
}
uint64_t windowID = 0;
nsresult rv = wrapper->GetData(&windowID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// In theory a tabChild should contain just 1 top window, but let's double
// check it comparing the windowID.
if (window->WindowID() != windowID) {
return NS_OK;
}
nsAutoString activeStr(aData);
bool active = activeStr.EqualsLiteral("active");
if (active != mAudioChannelActive) {
mAudioChannelActive = active;
unused << SendAudioChannelActivityNotification(audioChannel, active);
}
}
return NS_OK;
}
@ -2884,17 +2817,6 @@ TabChild::RecvDestroy()
observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
const nsAttrValue::EnumTable* table =
AudioChannelService::GetAudioChannelTable();
nsAutoCString topic;
for (uint32_t i = 0; table[i].tag; ++i) {
topic.Assign("audiochannel-activity-");
topic.Append(table[i].tag);
observerService->RemoveObserver(this, topic.get());
}
// XXX what other code in ~TabChild() should we be running here?
DestroyWindow();

Просмотреть файл

@ -659,7 +659,6 @@ private:
double mDefaultScale;
bool mIPCOpen;
bool mParentIsActive;
bool mAudioChannelActive;
bool mAsyncPanZoomEnabled;
CSSSize mUnscaledInnerSize;

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef TABMESSAGE_UTILS_H
#define TABMESSAGE_UTILS_H
#include "AudioChannelCommon.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "nsIDOMEvent.h"
@ -88,6 +89,14 @@ struct ParamTraits<mozilla::dom::AudioChannel>
}
};
template <>
struct ParamTraits<mozilla::dom::AudioChannelState>
: public ContiguousEnumSerializer<mozilla::dom::AudioChannelState,
mozilla::dom::AUDIO_CHANNEL_STATE_NORMAL,
mozilla::dom::AUDIO_CHANNEL_STATE_LAST>
{ };
template <>
struct ParamTraits<nsEventStatus>
: public ContiguousEnumSerializer<nsEventStatus,

Просмотреть файл

@ -8,7 +8,6 @@
#include "TabParent.h"
#include "AudioChannelService.h"
#include "AppProcessChecker.h"
#include "mozIApplication.h"
#ifdef ACCESSIBILITY
@ -2631,29 +2630,6 @@ TabParent::RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
return true;
}
bool
TabParent::RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
const bool& aActive)
{
if (aAudioChannel >= NUMBER_OF_AUDIO_CHANNELS) {
return false;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
nsAutoCString topic;
topic.Assign("audiochannel-activity-");
topic.Append(AudioChannelService::GetAudioChannelTable()[aAudioChannel].tag);
os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this),
topic.get(),
aActive ? MOZ_UTF16("active") : MOZ_UTF16("inactive"));
}
return true;
}
already_AddRefed<nsFrameLoader>
TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
{

Просмотреть файл

@ -461,9 +461,6 @@ protected:
const int32_t& aX, const int32_t& aY,
const int32_t& aCx, const int32_t& aCy) override;
virtual bool RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
const bool& aActive) override;
bool InitBrowserConfiguration(const nsCString& aURI,
BrowserConfiguration& aConfiguration);

Просмотреть файл

@ -298,11 +298,44 @@ static bool UseAudioChannelAPI()
return Preferences::GetBool("media.useAudioChannelAPI");
}
class EventProxyHandler final : public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
explicit EventProxyHandler(nsIDOMEventListener* aNode)
{
MOZ_ASSERT(aNode);
mWeakNode = do_GetWeakReference(aNode);
}
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
{
nsCOMPtr<nsIDOMEventListener> listener = do_QueryReferent(mWeakNode);
if (!listener) {
return NS_OK;
}
auto node = static_cast<AudioDestinationNode*>(listener.get());
return node->HandleEvent(aEvent);
}
private:
~EventProxyHandler()
{ }
nsWeakPtr mWeakNode;
};
NS_IMPL_ISUPPORTS(EventProxyHandler, nsIDOMEventListener)
NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode,
mAudioChannelAgent,
mAudioChannelAgent, mEventProxyHelper,
mOfflineRenderingPromise)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
@ -375,6 +408,13 @@ AudioDestinationNode::DestroyAudioChannelAgent()
if (mAudioChannelAgent && !Context()->IsOffline()) {
mAudioChannelAgent->StopPlaying();
mAudioChannelAgent = nullptr;
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
mEventProxyHelper,
/* useCapture = */ true);
}
}
@ -478,30 +518,65 @@ AudioDestinationNode::StartRendering(Promise* aPromise)
}
void
AudioDestinationNode::SetCanPlay(float aVolume, bool aMuted)
AudioDestinationNode::SetCanPlay(bool aCanPlay)
{
if (!mStream) {
return;
}
mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, !aMuted);
mStream->SetAudioOutputVolume(&gWebAudioOutputKey, aVolume);
mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, aCanPlay);
}
NS_IMETHODIMP
AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted)
AudioDestinationNode::HandleEvent(nsIDOMEvent* aEvent)
{
if (aMuted != mAudioChannelAgentPlaying) {
mAudioChannelAgentPlaying = aMuted;
nsAutoString type;
aEvent->GetType(type);
if (UseAudioChannelAPI()) {
Context()->DispatchTrustedEvent(
!aMuted ? NS_LITERAL_STRING("mozinterruptend")
: NS_LITERAL_STRING("mozinterruptbegin"));
}
if (!type.EqualsLiteral("visibilitychange")) {
return NS_ERROR_FAILURE;
}
SetCanPlay(aVolume, aMuted);
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
bool isActive = false;
docshell->GetIsActive(&isActive);
mAudioChannelAgent->SetVisibilityState(isActive);
return NS_OK;
}
NS_IMETHODIMP
AudioDestinationNode::CanPlayChanged(int32_t aCanPlay)
{
bool playing = aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL;
if (playing == mAudioChannelAgentPlaying) {
return NS_OK;
}
mAudioChannelAgentPlaying = playing;
SetCanPlay(playing);
if (UseAudioChannelAPI()) {
Context()->DispatchTrustedEvent(
playing ? NS_LITERAL_STRING("mozinterruptend")
: NS_LITERAL_STRING("mozinterruptbegin"));
}
return NS_OK;
}
NS_IMETHODIMP
AudioDestinationNode::WindowVolumeChanged()
{
MOZ_ASSERT(mAudioChannelAgent);
if (!mStream) {
return NS_OK;
}
float volume;
nsresult rv = mAudioChannelAgent->GetWindowVolume(&volume);
NS_ENSURE_SUCCESS(rv, rv);
mStream->SetAudioOutputVolume(&gWebAudioOutputKey, volume);
return NS_OK;
}
@ -579,6 +654,20 @@ AudioDestinationNode::CreateAudioChannelAgent()
return;
}
if (!mEventProxyHelper) {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
if (target) {
// We use a proxy because otherwise the event listerner would hold a
// reference of the destination node, and by extension, everything
// connected to it.
mEventProxyHelper = new EventProxyHandler(this);
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
mEventProxyHelper,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
}
}
if (mAudioChannelAgent) {
mAudioChannelAgent->StopPlaying();
}
@ -588,9 +677,16 @@ AudioDestinationNode::CreateAudioChannelAgent()
static_cast<int32_t>(mAudioChannel),
this);
// The AudioChannelAgent must start playing immediately in order to avoid
// race conditions with mozinterruptbegin/end events.
InputMuted(false);
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
if (docshell) {
bool isActive = false;
docshell->GetIsActive(&isActive);
mAudioChannelAgent->SetVisibilityState(isActive);
// The AudioChannelAgent must start playing immediately in order to avoid
// race conditions with mozinterruptbegin/end events.
InputMuted(false);
}
}
void
@ -675,14 +771,13 @@ AudioDestinationNode::InputMuted(bool aMuted)
return;
}
float volume = 0.0;
bool muted = true;
nsresult rv = mAudioChannelAgent->StartPlaying(&volume, &muted);
int32_t state = 0;
nsresult rv = mAudioChannelAgent->StartPlaying(&state);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
WindowVolumeChanged(volume, muted);
CanPlayChanged(state);
}
} // dom namespace

Просмотреть файл

@ -9,14 +9,18 @@
#include "mozilla/dom/AudioChannelBinding.h"
#include "AudioNode.h"
#include "nsIDOMEventListener.h"
#include "nsIAudioChannelAgent.h"
#include "AudioChannelCommon.h"
namespace mozilla {
namespace dom {
class AudioContext;
class EventProxyHandler;
class AudioDestinationNode final : public AudioNode
, public nsIDOMEventListener
, public nsIAudioChannelAgentCallback
, public MainThreadMediaStreamListener
{
@ -57,6 +61,9 @@ public:
void OfflineShutdown();
// nsIDOMEventListener - by proxy
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
AudioChannel MozAudioChannelType() const;
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
@ -90,7 +97,7 @@ protected:
private:
bool CheckAudioChannelPermissions(AudioChannel aValue);
void SetCanPlay(float aVolume, bool aMuted);
void SetCanPlay(bool aCanPlay);
void NotifyStableState();
void ScheduleStableStateNotification();
@ -100,6 +107,7 @@ private:
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
nsRefPtr<EventProxyHandler> mEventProxyHelper;
nsRefPtr<Promise> mOfflineRenderingPromise;
// Audio Channel Type.

Просмотреть файл

@ -18,6 +18,8 @@ MOCHITEST_MANIFESTS += [
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
EXPORTS += [
'AlignedTArray.h',
'AudioContext.h',

Просмотреть файл

@ -0,0 +1,8 @@
[DEFAULT]
support-files =
browser_mozAudioChannel.html
browser_mozAudioChannel_muted.html
[browser_mozAudioChannel.js]
[browser_mozAudioChannel_muted.js]
skip-if = e10s

Просмотреть файл

@ -0,0 +1,33 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<meta charset="utf-8">
<title>Test for mozinterruptbegin/end in AudioContext</title>
<script type="application/javascript">
var ac = new AudioContext();
function createEvent(msg) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('testmozchannel', true, true, { msg: msg });
dispatchEvent(event);
}
ac.onmozinterruptbegin = function(evt) {
createEvent('mozinterruptbegin');
}
ac.addEventListener('mozinterruptend', function() {
createEvent('mozinterruptend');
}, false);
var buffer = ac.createBuffer(1, 2048, ac.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / ac.sampleRate);
}
var source = ac.createBufferSource();
source.buffer = buffer;
source.connect(ac.destination);
source.loop = true;
source.start(0);
</script>

Просмотреть файл

@ -0,0 +1,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/. */
function whenBrowserLoaded(aBrowser, aCallback) {
aBrowser.addEventListener("load", function onLoad(event) {
if (event.target == aBrowser.contentDocument) {
aBrowser.removeEventListener("load", onLoad, true);
executeSoon(aCallback);
}
}, true);
}
function whenBrowserUnloaded(aBrowser, aCallback) {
aBrowser.addEventListener("unload", function onUnload() {
aBrowser.removeEventListener("unload", onUnload, true);
executeSoon(aCallback);
}, true);
}
var event;
var next = function() {}
function eventListener(evt) {
info("Event has been received!");
is(evt.detail.msg, event, "AudioContext has been received the right event: " + event);
next();
}
function test() {
waitForExplicitFinish();
let testURL = "http://mochi.test:8888/browser/" +
"dom/media/webaudio/test/browser_mozAudioChannel.html";
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
["media.useAudioChannelAPI", true ],
["media.useAudioChannelService", true ]]},
function() {
let tab1 = gBrowser.addTab(testURL);
gBrowser.selectedTab = tab1;
whenBrowserLoaded(tab1.linkedBrowser, function() {
let doc = tab1.linkedBrowser.contentDocument;
tab1.linkedBrowser.contentWindow.addEventListener('testmozchannel', eventListener, false);
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "telephony" ]]},
function() {
event = 'mozinterruptbegin';
next = function() {
info("Next is called.");
event = 'mozinterruptend';
next = function() {
info("Next is called again.");
tab1.linkedBrowser.contentWindow.removeEventListener('testmozchannel', eventListener);
gBrowser.removeTab(tab1);
finish();
}
info("Unloading a tab...");
whenBrowserUnloaded(tab2.linkedBrowser, function() { info("Tab unloaded."); });
executeSoon(function() {
gBrowser.removeTab(tab2);
gBrowser.selectedTab = tab1;
});
}
let tab2 = gBrowser.addTab(testURL);
gBrowser.selectedTab = tab2;
info("Loading the tab...");
whenBrowserLoaded(tab2.linkedBrowser, function() { info("Tab restored."); });
}
);
});
}
);
}

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<meta charset="utf-8">
<title>Test for mozinterruptbegin/end in AudioContext</title>
mozAudioChannelTest = <span id="mozAudioChannelTest">FAIL</span>
<script type="application/javascript">
var ac = new AudioContext();
ac.onmozinterruptbegin = function(evt) {
document.getElementById("mozAudioChannelTest").innerHTML = "mozinterruptbegin";
}
ac.addEventListener('mozinterruptend', function() {
document.getElementById("mozAudioChannelTest").innerHTML = "mozinterruptend";
}, false);
document.getElementById("mozAudioChannelTest").innerHTML = "READY";
</script>

Просмотреть файл

@ -0,0 +1,72 @@
/* 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/. */
function whenBrowserLoaded(aBrowser, aCallback) {
aBrowser.addEventListener("load", function onLoad(event) {
if (event.target == aBrowser.contentDocument) {
aBrowser.removeEventListener("load", onLoad, true);
executeSoon(aCallback);
}
}, true);
}
function whenTabRestored(aTab, aCallback) {
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
aTab.removeEventListener("SSTabRestored", onRestored, true);
executeSoon(function executeWhenTabRestored() {
aCallback();
});
}, true);
}
function whenBrowserUnloaded(aBrowser, aCallback) {
aBrowser.addEventListener("unload", function onUnload() {
aBrowser.removeEventListener("unload", onUnload, true);
executeSoon(aCallback);
}, true);
}
function test() {
waitForExplicitFinish();
let testURL = "http://mochi.test:8888/browser/" +
"dom/media/webaudio/test/browser_mozAudioChannel_muted.html";
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
["media.useAudioChannelAPI", true ],
["media.useAudioChannelService", true ]]},
function() {
let tab1 = gBrowser.addTab(testURL);
gBrowser.selectedTab = tab1;
whenBrowserLoaded(tab1.linkedBrowser, function() {
let doc = tab1.linkedBrowser.contentDocument;
is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
"Test is ready to run");
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "telephony" ]]},
function() {
let tab2 = gBrowser.duplicateTab(tab1);
gBrowser.selectedTab = tab2;
whenTabRestored(tab2, function() {
is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptbegin",
"AudioContext should be muted by the second tab.");
whenBrowserUnloaded(tab2.linkedBrowser, function() {
is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptend",
"AudioContext should be muted by the second tab.");
gBrowser.removeTab(tab1);
finish();
});
gBrowser.removeTab(tab2);
gBrowser.selectedTab = tab1;
});
}
);
});
}
);
}

Просмотреть файл

@ -201,8 +201,8 @@ SpeakerManager::HandleEvent(nsIDOMEvent* aEvent)
// currently playing in the app itself, if application switch to
// the background, we switch 'speakerforced' to false.
if (!mVisible && mForcespeaker) {
nsRefPtr<AudioChannelService> audioChannelService =
AudioChannelService::GetOrCreate();
AudioChannelService* audioChannelService =
AudioChannelService::GetOrCreateAudioChannelService();
if (audioChannelService && !audioChannelService->AnyAudioChannelIsActive()) {
service->ForceSpeaker(false, mVisible);
}

Просмотреть файл

@ -194,15 +194,18 @@ SpeakerManagerService::SpeakerManagerService()
obs->AddObserver(this, "ipc:content-shutdown", false);
}
}
nsRefPtr<AudioChannelService> audioChannelService =
AudioChannelService::GetOrCreate();
audioChannelService->RegisterSpeakerManager(this);
AudioChannelService* audioChannelService =
AudioChannelService::GetOrCreateAudioChannelService();
if (audioChannelService) {
audioChannelService->RegisterSpeakerManager(this);
}
}
SpeakerManagerService::~SpeakerManagerService()
{
MOZ_COUNT_DTOR(SpeakerManagerService);
nsRefPtr<AudioChannelService> audioChannelService =
AudioChannelService::GetOrCreate();
audioChannelService->UnregisterSpeakerManager(this);
AudioChannelService* audioChannelService =
AudioChannelService::GetOrCreateAudioChannelService();
if (audioChannelService)
audioChannelService->UnregisterSpeakerManager(this);
}

Просмотреть файл

@ -96,7 +96,7 @@ SpeakerManagerServiceChild::SetAudioChannelActive(bool aIsActive)
SpeakerManagerServiceChild::SpeakerManagerServiceChild()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetOrCreate();
AudioChannelService* audioChannelService = AudioChannelService::GetOrCreateAudioChannelService();
if (audioChannelService) {
audioChannelService->RegisterSpeakerManager(this);
}
@ -105,7 +105,7 @@ SpeakerManagerServiceChild::SpeakerManagerServiceChild()
SpeakerManagerServiceChild::~SpeakerManagerServiceChild()
{
nsRefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetOrCreate();
AudioChannelService* audioChannelService = AudioChannelService::GetOrCreateAudioChannelService();
if (audioChannelService) {
audioChannelService->UnregisterSpeakerManager(this);
}

Просмотреть файл

@ -131,7 +131,7 @@ AudioChannelManager::NotifyVolumeControlChannelChanged()
bool isActive = false;
docshell->GetIsActive(&isActive);
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
AudioChannelService* service = AudioChannelService::GetOrCreateAudioChannelService();
if (isActive) {
service->SetDefaultVolumeControlChannel(mVolumeChannel, isActive);
} else {

Просмотреть файл

@ -356,7 +356,7 @@ AudioManager::HandleAudioChannelProcessChanged()
return;
}
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
AudioChannelService *service = AudioChannelService::GetOrCreateAudioChannelService();
MOZ_ASSERT(service);
bool telephonyChannelIsActive = service->TelephonyChannelIsActive();
@ -651,13 +651,8 @@ AudioManager::SetPhoneState(int32_t aState)
}
// Telephony can always play.
float volume = 0.0;
bool muted = true;
nsresult rv = mPhoneAudioAgent->StartPlaying(&volume, &muted);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
int32_t canPlay;
mPhoneAudioAgent->StartPlaying(&canPlay);
}
return NS_OK;

Просмотреть файл

@ -220,8 +220,6 @@ var interfaceNamesInGlobalScope =
permission: ["bluetooth"]},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "BoxObject", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "BrowserElementAudioChannel", b2g: true, permission: ["browser"] },
// IMPORTANT: Do not change this list without review from a DOM peer!
"BroadcastChannel",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -1,37 +0,0 @@
/* -*- Mode: IDL; 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/.
*/
[Pref="dom.mozBrowserFramesEnabled",
CheckPermissions="browser"]
interface BrowserElementAudioChannel : EventTarget {
readonly attribute AudioChannel name;
// This event is dispatched when this audiochannel is actually in used by the
// app or one of the sub-iframes.
attribute EventHandler onactivestatechanged;
[Throws]
DOMRequest getVolume();
[Throws]
DOMRequest setVolume(float aVolume);
[Throws]
DOMRequest getMuted();
[Throws]
DOMRequest setMuted(boolean aMuted);
[Throws]
DOMRequest isActive();
};
partial interface BrowserElementPrivileged {
[Constant, Cached, Throws,
Pref="dom.mozBrowserFramesEnabled",
CheckPermissions="browser"]
readonly attribute sequence<BrowserElementAudioChannel> allowedAudioChannels;
};

Просмотреть файл

@ -57,7 +57,6 @@ WEBIDL_FILES = [
'BoxObject.webidl',
'BroadcastChannel.webidl',
'BrowserElement.webidl',
'BrowserElementAudioChannel.webidl',
'BrowserElementDictionaries.webidl',
'Cache.webidl',
'CacheStorage.webidl',

Просмотреть файл

@ -631,7 +631,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(Geolocation, Init)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioChannelService, AudioChannelService::GetOrCreate)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioChannelService, AudioChannelService::GetOrCreateAudioChannelService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DataStoreService, DataStoreService::GetOrCreate)

Просмотреть файл

@ -4957,8 +4957,6 @@ pref("reader.toolbar.vertical", true);
pref("media.gmp.insecure.allow", false);
#endif
pref("dom.audiochannel.mutedByDefault", false);
// Use vsync aligned rendering. b2g prefs are in b2g.js.
// Hardware vsync supported on windows, os x, and b2g.
// Linux and fennec will use software vsync.