mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset bcfbdb934c37 (bug 1113086) for breaking cpp tests with timeouts in TestAudioChannelService.exe
This commit is contained in:
parent
119564601c
commit
6a80a5a324
@ -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,12 +100,12 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
|
||||
}
|
||||
|
||||
if (aWindow) {
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
|
||||
MOZ_ASSERT(topWindow);
|
||||
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow);
|
||||
if (!pWindow->IsInnerWindow()) {
|
||||
pWindow = pWindow->GetCurrentInnerWindow();
|
||||
}
|
||||
|
||||
mWindow = do_QueryInterface(topWindow);
|
||||
mWindow = mWindow->GetOuterWindow();
|
||||
mWindow = pWindow.forget();
|
||||
}
|
||||
|
||||
mAudioChannelType = aChannelType;
|
||||
@ -102,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;
|
||||
}
|
||||
@ -134,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()
|
||||
{
|
||||
@ -158,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,15 +50,15 @@ 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
|
||||
|
24
dom/audiochannel/AudioChannelCommon.h
Normal file
24
dom/audiochannel/AudioChannelCommon.h
Normal file
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,11 +7,12 @@
|
||||
#ifndef mozilla_dom_audiochannelservice_h__
|
||||
#define mozilla_dom_audiochannelservice_h__
|
||||
|
||||
#include "nsIAudioChannelService.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "AudioChannelCommon.h"
|
||||
#include "AudioChannelAgent.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsClassHashtable.h"
|
||||
@ -25,23 +26,27 @@ 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.
|
||||
@ -52,45 +57,40 @@ public:
|
||||
* 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
|
||||
@ -125,69 +125,161 @@ public:
|
||||
static void GetAudioChannelString(AudioChannel aChannel, nsAString& aString);
|
||||
static void GetDefaultAudioChannelString(nsAString& aString);
|
||||
|
||||
void Notify(uint64_t aWindowID);
|
||||
void Notify();
|
||||
|
||||
private:
|
||||
AudioChannelService();
|
||||
~AudioChannelService();
|
||||
protected:
|
||||
void SendNotification();
|
||||
|
||||
/**
|
||||
* Send the audio-channel-changed notification for the given process ID if
|
||||
* needed.
|
||||
*/
|
||||
void SendAudioChannelChangedNotification(uint64_t aChildID);
|
||||
|
||||
/* 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);
|
||||
|
||||
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(false)
|
||||
, mNumberOfAgents(0)
|
||||
AudioChannelState CheckTelephonyPolicy(AudioChannel aChannel,
|
||||
uint64_t aChildID);
|
||||
void RegisterTelephonyChild(uint64_t aChildID);
|
||||
void UnregisterTelephonyChild(uint64_t aChildID);
|
||||
|
||||
AudioChannelService();
|
||||
virtual ~AudioChannelService();
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
float mVolume;
|
||||
bool mMuted;
|
||||
|
||||
uint32_t mNumberOfAgents;
|
||||
AudioChannel mChannel;
|
||||
bool mElementHidden;
|
||||
AudioChannelState mState;
|
||||
const bool mWithVideo;
|
||||
};
|
||||
|
||||
struct AudioChannelWindow final
|
||||
{
|
||||
AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS];
|
||||
nsClassHashtable<nsPtrHashKey<AudioChannelAgent>, AudioChannel> mAgents;
|
||||
};
|
||||
|
||||
AudioChannelWindow&
|
||||
GetOrCreateWindowData(nsPIDOMWindow* aWindow);
|
||||
|
||||
static PLDHashOperator
|
||||
TelephonyChannelIsActiveEnumerator(const uint64_t& aWindowID,
|
||||
nsAutoPtr<AudioChannelWindow>& aWinData,
|
||||
void *aPtr);
|
||||
|
||||
static PLDHashOperator
|
||||
AnyAudioChannelIsActiveEnumerator(const uint64_t& aWindowID,
|
||||
nsAutoPtr<AudioChannelWindow>& aWinData,
|
||||
void *aPtr);
|
||||
|
||||
static PLDHashOperator
|
||||
RefreshAgentsVolumeEnumerator(AudioChannelAgent* aAgent,
|
||||
AudioChannel* aUnused,
|
||||
void *aPtr);
|
||||
|
||||
static PLDHashOperator
|
||||
NotifyEnumerator(AudioChannelAgent* aAgent,
|
||||
AudioChannel* aAudioChannel,
|
||||
void* aUnused);
|
||||
AudioChannelAgentData* aData, void *aUnused);
|
||||
|
||||
nsClassHashtable<nsUint64HashKey, AudioChannelWindow> mWindows;
|
||||
static PLDHashOperator
|
||||
RefreshAgentsVolumeEnumerator(AudioChannelAgent* aAgent,
|
||||
AudioChannelAgentData* aUnused,
|
||||
void *aPtr);
|
||||
|
||||
static PLDHashOperator
|
||||
CountWindowEnumerator(AudioChannelAgent* aAgent,
|
||||
AudioChannelAgentData* aUnused,
|
||||
void *aPtr);
|
||||
|
||||
static PLDHashOperator
|
||||
WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
|
||||
nsAutoPtr<AudioChannelAgentData>& aData,
|
||||
void *aPtr);
|
||||
|
||||
// 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;
|
||||
|
||||
nsCOMPtr<nsITimer> mDeferTelChannelTimer;
|
||||
bool mTimerElementHidden;
|
||||
uint64_t mTimerChildID;
|
||||
|
||||
uint64_t mDefChannelChildID;
|
||||
|
||||
// This is needed for IPC comunication between
|
||||
|
168
dom/audiochannel/AudioChannelServiceChild.cpp
Normal file
168
dom/audiochannel/AudioChannelServiceChild.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
62
dom/audiochannel/AudioChannelServiceChild.h
Normal file
62
dom/audiochannel/AudioChannelServiceChild.h
Normal file
@ -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(363ff8d3-5bd2-485a-84ac-125062cbdc19)]
|
||||
[uuid(2b0222a5-8f7b-49d2-9ab8-cd01b744b23e)]
|
||||
interface nsIAudioChannelAgent : nsISupports
|
||||
{
|
||||
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
|
||||
@ -80,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
|
||||
@ -94,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.
|
||||
@ -105,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);
|
||||
};
|
18
dom/audiochannel/tests/AudioChannelChromeScript.js
Normal file
18
dom/audiochannel/tests/AudioChannelChromeScript.js
Normal file
@ -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);
|
||||
});
|
669
dom/audiochannel/tests/TestAudioChannelService.cpp
Normal file
669
dom/audiochannel/tests/TestAudioChannelService.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
BIN
dom/audiochannel/tests/audio.ogg
Normal file
BIN
dom/audiochannel/tests/audio.ogg
Normal file
Binary file not shown.
99
dom/audiochannel/tests/file_audio.html
Normal file
99
dom/audiochannel/tests/file_audio.html
Normal file
@ -0,0 +1,99 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test audio-channel-changed & visible-audio-channel-changed mozChromeEvent</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script>
|
||||
var normalAudio;
|
||||
var contentAudio;
|
||||
var notificationAudio;
|
||||
var alarmAudio;
|
||||
var telephonyAudio;
|
||||
var ringerAudio;
|
||||
var publicnotificationAudio;
|
||||
|
||||
function playWithAudioType(audio, type) {
|
||||
audio.mozAudioChannelType = type;
|
||||
audio.src = "test.ogg";
|
||||
audio.loop = true;
|
||||
|
||||
audio.play();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
// normal channel.
|
||||
normalAudio = new Audio();
|
||||
playWithAudioType(normalAudio, 'normal');
|
||||
|
||||
// content channel.
|
||||
contentAudio = new Audio();
|
||||
playWithAudioType(contentAudio, 'content');
|
||||
|
||||
// notification channel.
|
||||
notificationAudio = new Audio();
|
||||
playWithAudioType(notificationAudio, 'notification');
|
||||
|
||||
// alarm channel.
|
||||
alarmAudio = new Audio();
|
||||
playWithAudioType(alarmAudio, 'alarm');
|
||||
|
||||
// telephony channel.
|
||||
telephonyAudio = new Audio();
|
||||
playWithAudioType(telephonyAudio, 'telephony');
|
||||
|
||||
// ringer channel.
|
||||
ringerAudio = new Audio();
|
||||
playWithAudioType(ringerAudio, 'ringer');
|
||||
|
||||
// publicnotification channel.
|
||||
publicnotificationAudio = new Audio();
|
||||
playWithAudioType(publicnotificationAudio, 'publicnotification');
|
||||
|
||||
window.addEventListener('hashchange', function(event) {
|
||||
if (location.hash == "#pauseAudio") {
|
||||
publicnotificationAudio.pause();
|
||||
ringerAudio.pause();
|
||||
telephonyAudio.pause();
|
||||
}
|
||||
|
||||
if (location.hash == "#pauseAudioFollowing") {
|
||||
alarmAudio.pause();
|
||||
notificationAudio.pause();
|
||||
contentAudio.pause();
|
||||
normalAudio.pause();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
function checkBackgroundStatus() {
|
||||
if (location.hash == "#fg") {
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.hidden) {
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', function visibilityChange() {
|
||||
if (document.hidden) {
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "audio-channel-content", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-notification", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-alarm", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-telephony", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-ringer", "allow": 1, "context": document },
|
||||
{ "type": "audio-channel-publicnotification", "allow": 1, "context": document }],
|
||||
checkBackgroundStatus);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
18
dom/audiochannel/tests/file_telephonyPolicy.html
Normal file
18
dom/audiochannel/tests/file_telephonyPolicy.html
Normal file
@ -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>
|
11
dom/audiochannel/tests/mochitest.ini
Normal file
11
dom/audiochannel/tests/mochitest.ini
Normal file
@ -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')
|
16
dom/audiochannel/tests/moz.build
Normal file
16
dom/audiochannel/tests/moz.build
Normal file
@ -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
|
209
dom/audiochannel/tests/test_audioChannelChange.html
Normal file
209
dom/audiochannel/tests/test_audioChannelChange.html
Normal file
@ -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>
|
87
dom/audiochannel/tests/test_telephonyPolicy.html
Normal file
87
dom/audiochannel/tests/test_telephonyPolicy.html
Normal file
@ -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;
|
||||
|
@ -2791,11 +2791,64 @@ ContentParent::RecvFirstIdle()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAudioChannelGetState(const AudioChannel& aChannel,
|
||||
const bool& aElementHidden,
|
||||
const bool& aElementWasHidden,
|
||||
AudioChannelState* aState)
|
||||
{
|
||||
nsRefPtr<AudioChannelService> service =
|
||||
AudioChannelService::GetOrCreateAudioChannelService();
|
||||
*aState = AUDIO_CHANNEL_STATE_NORMAL;
|
||||
MOZ_ASSERT(service);
|
||||
*aState = service->GetStateInternal(aChannel, mChildID,
|
||||
aElementHidden, aElementWasHidden);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAudioChannelRegisterType(const AudioChannel& aChannel,
|
||||
const bool& aWithVideo)
|
||||
{
|
||||
nsRefPtr<AudioChannelService> service =
|
||||
AudioChannelService::GetOrCreateAudioChannelService();
|
||||
MOZ_ASSERT(service);
|
||||
service->RegisterType(aChannel, mChildID, aWithVideo);
|
||||
|
||||
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::GetOrCreate();
|
||||
nsRefPtr<AudioChannelService> service =
|
||||
AudioChannelService::GetOrCreateAudioChannelService();
|
||||
MOZ_ASSERT(service);
|
||||
service->SetDefaultVolumeControlChannelInternal(aChannel,
|
||||
aHidden, mChildID);
|
||||
|
@ -752,6 +752,19 @@ 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 RecvGetSystemMemory(const uint64_t& getterId) override;
|
||||
|
@ -548,10 +548,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();
|
||||
|
||||
/**
|
||||
@ -864,6 +871,17 @@ parent:
|
||||
// Tell the parent that the child has gone idle for the first time
|
||||
async FirstIdle();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -890,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
|
||||
@ -973,27 +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) {
|
||||
nsAutoString active(aData);
|
||||
unused << SendAudioChannelActivityNotification(audioChannel,
|
||||
active.Equals(NS_LITERAL_STRING("active")));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2856,17 +2819,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();
|
||||
|
||||
|
@ -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
|
||||
@ -2647,29 +2646,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
|
||||
{
|
||||
|
@ -462,9 +462,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',
|
||||
|
8
dom/media/webaudio/test/browser.ini
Normal file
8
dom/media/webaudio/test/browser.ini
Normal file
@ -0,0 +1,8 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
browser_mozAudioChannel.html
|
||||
browser_mozAudioChannel_muted.html
|
||||
|
||||
[browser_mozAudioChannel.js]
|
||||
[browser_mozAudioChannel_muted.js]
|
||||
skip-if = e10s
|
33
dom/media/webaudio/test/browser_mozAudioChannel.html
Normal file
33
dom/media/webaudio/test/browser_mozAudioChannel.html
Normal file
@ -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>
|
80
dom/media/webaudio/test/browser_mozAudioChannel.js
Normal file
80
dom/media/webaudio/test/browser_mozAudioChannel.js
Normal file
@ -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."); });
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
21
dom/media/webaudio/test/browser_mozAudioChannel_muted.html
Normal file
21
dom/media/webaudio/test/browser_mozAudioChannel_muted.html
Normal file
@ -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>
|
72
dom/media/webaudio/test/browser_mozAudioChannel_muted.js
Normal file
72
dom/media/webaudio/test/browser_mozAudioChannel_muted.js
Normal file
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user