зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
291696aa87
Коммит
f23d866f51
|
@ -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;
|
||||
}
|
||||
|
Двоичный файл не отображается.
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче