Bug 1320005 - don't show the 'play tab' icon for the media element without audio track.
MozReview-Commit-ID: K42I0yWaI7N
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -186,30 +186,31 @@ AudioChannelAgent::InitInternal(nsPIDOMW
"owner = %p, hasCallback = %d\n", this, mAudioChannelType,
mWindow.get(), (!!mCallback || !!mWeakCallback)));
return NS_OK;
}
NS_IMETHODIMP
AudioChannelAgent::NotifyStartedPlaying(AudioPlaybackConfig* aConfig,
- bool aAudible)
+ uint8_t aAudible)
{
if (NS_WARN_IF(!aConfig)) {
return NS_ERROR_FAILURE;
}
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
service == nullptr || mIsRegToService) {
return NS_ERROR_FAILURE;
}
- MOZ_ASSERT(AudioChannelService::AudibleState::eAudible == true &&
- AudioChannelService::AudibleState::eNotAudible == false);
+ MOZ_ASSERT(AudioChannelService::AudibleState::eNotAudible == 0 &&
+ AudioChannelService::AudibleState::eMaybeAudible == 1 &&
+ AudioChannelService::AudibleState::eAudible == 2);
service->RegisterAudioChannelAgent(this,
static_cast<AudioChannelService::AudibleState>(aAudible));
AudioPlaybackConfig config = service->GetMediaConfig(mWindow,
mAudioChannelType);
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
("AudioChannelAgent, NotifyStartedPlaying, this = %p, "
@@ -237,17 +238,17 @@ AudioChannelAgent::NotifyStoppedPlaying(
service->UnregisterAudioChannelAgent(this);
}
mIsRegToService = false;
return NS_OK;
}
NS_IMETHODIMP
-AudioChannelAgent::NotifyStartedAudible(bool aAudible, uint32_t aReason)
+AudioChannelAgent::NotifyStartedAudible(uint8_t aAudible, uint32_t aReason)
{
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
("AudioChannelAgent, NotifyStartedAudible, this = %p, "
"audible = %d, reason = %d\n", this, aAudible, aReason));
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
if (NS_WARN_IF(!service)) {
return NS_ERROR_FAILURE;
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -1222,24 +1222,24 @@ void
AudioChannelService::AudioChannelWindow::AppendAgent(AudioChannelAgent* aAgent,
AudibleState aAudible)
{
MOZ_ASSERT(aAgent);
RequestAudioFocus(aAgent);
AppendAgentAndIncreaseAgentsNum(aAgent);
AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
- if (aAudible) {
+ if (aAudible == AudibleState::eAudible) {
AudioAudibleChanged(aAgent,
AudibleState::eAudible,
AudibleChangedReasons::eDataAudibleChanged);
- } else if (IsEnableAudioCompetingForAllAgents() && !aAudible) {
+ } else if (IsEnableAudioCompetingForAllAgents() &&
+ aAudible != AudibleState::eAudible) {
NotifyAudioCompetingChanged(aAgent, true);
}
- MaybeNotifyMediaBlocked(aAgent);
}
void
AudioChannelService::AudioChannelWindow::RemoveAgent(AudioChannelAgent* aAgent)
{
MOZ_ASSERT(aAgent);
RemoveAgentAndReduceAgentsNum(aAgent);
@@ -1300,23 +1300,26 @@ AudioChannelService::AudioChannelWindow:
void
AudioChannelService::AudioChannelWindow::AudioAudibleChanged(AudioChannelAgent* aAgent,
AudibleState aAudible,
AudibleChangedReasons aReason)
{
MOZ_ASSERT(aAgent);
- if (aAudible) {
+ if (aAudible == AudibleState::eAudible) {
AppendAudibleAgentIfNotContained(aAgent, aReason);
} else {
RemoveAudibleAgentIfContained(aAgent, aReason);
}
- NotifyAudioCompetingChanged(aAgent, aAudible);
+ NotifyAudioCompetingChanged(aAgent, aAudible == AudibleState::eAudible);
+ if (aAudible != AudibleState::eNotAudible) {
+ MaybeNotifyMediaBlocked(aAgent);
+ }
}
void
AudioChannelService::AudioChannelWindow::AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
AudibleChangedReasons aReason)
{
MOZ_ASSERT(aAgent);
MOZ_ASSERT(mAgents.Contains(aAgent));
@@ -1363,17 +1366,19 @@ AudioChannelService::AudioChannelWindow:
}
void
AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
AudibleState aAudible,
AudibleChangedReasons aReason)
{
RefPtr<AudioPlaybackRunnable> runnable =
- new AudioPlaybackRunnable(aWindow, aAudible, aReason);
+ new AudioPlaybackRunnable(aWindow,
+ aAudible == AudibleState::eAudible,
+ aReason);
DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
}
void
AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID,
AudioChannel aChannel,
bool aActive)
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -60,19 +60,25 @@ public:
class AudioChannelService final : public nsIAudioChannelService
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIAUDIOCHANNELSERVICE
- enum AudibleState : bool {
- eAudible = true,
- eNotAudible = false
+ /**
+ * eNotAudible : agent is not audible
+ * eMaybeAudible : agent is not audible now, but it might be audible later
+ * eAudible : agent is audible now
+ */
+ enum AudibleState : uint8_t {
+ eNotAudible = 0,
+ eMaybeAudible = 1,
+ eAudible = 2
};
enum AudioCaptureState : bool {
eCapturing = true,
eNotCapturing = false
};
enum AudibleChangedReasons : uint32_t {
--- a/dom/audiochannel/nsIAudioChannelAgent.idl
+++ b/dom/audiochannel/nsIAudioChannelAgent.idl
@@ -158,17 +158,17 @@ interface nsIAudioChannelAgent : nsISupp
/**
* Notify the agent that we want to start playing.
* Note: Gecko component SHOULD call this function first then start to
* play audio stream only when return value is true.
*
* @param config
* It contains the playback related states (volume/mute/suspend)
*/
- void notifyStartedPlaying(in AudioPlaybackConfig config, in bool audible);
+ void notifyStartedPlaying(in AudioPlaybackConfig config, in uint8_t audible);
/**
* Notify the agent we no longer want to play.
*
* Note : even if notifyStartedPlaying() returned false, the agent would
* still be registered with the audio channel service and receive callbacks
* for status changes. So notifyStoppedPlaying must still eventually be
* called to unregister the agent with the channel service.
@@ -178,10 +178,10 @@ interface nsIAudioChannelAgent : nsISupp
/**
* Notify agent that we already start producing audible data.
*
* Note : sometime audio might become silent during playing, this method is used to
* notify the actually audible state to other services which want to know
* about that, ex. tab sound indicator.
*/
- void notifyStartedAudible(in bool audible, in uint32_t reason);
+ void notifyStartedAudible(in uint8_t audible, in uint32_t reason);
};
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -748,17 +748,17 @@ public:
void
NotifyAudioPlaybackChanged(AudibleChangedReasons aReason)
{
MOZ_ASSERT(!mIsShutDown);
if (!IsPlayingStarted()) {
return;
}
- bool newAudibleState = IsOwnerAudible();
+ AudibleState newAudibleState = IsOwnerAudible();
if (mIsOwnerAudible == newAudibleState) {
return;
}
mIsOwnerAudible = newAudibleState;
mAudioChannelAgent->NotifyStartedAudible(mIsOwnerAudible, aReason);
}
@@ -971,35 +971,35 @@ private:
bool
IsSuspended() const
{
return (mSuspended == nsISuspendedTypes::SUSPENDED_PAUSE ||
mSuspended == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE ||
mSuspended == nsISuspendedTypes::SUSPENDED_BLOCK);
}
- bool
+ AudibleState
IsOwnerAudible() const
{
// Muted or the volume should not be ~0
if (mOwner->Muted() || (std::fabs(mOwner->Volume()) <= 1e-7)) {
- return false;
- }
-
- // No sound can be heard during suspending.
- if (IsSuspended()) {
- return false;
- }
-
- // Silent audio track.
- if (!mOwner->mIsAudioTrackAudible) {
- return false;
- }
-
- return true;
+ return AudioChannelService::AudibleState::eNotAudible;
+ }
+
+ // No audio track.
+ if (!mOwner->HasAudio()) {
+ return AudioChannelService::AudibleState::eNotAudible;
+ }
+
+ // Might be audible but not yet.
+ if (mOwner->HasAudio() && !mOwner->mIsAudioTrackAudible) {
+ return AudioChannelService::AudibleState::eMaybeAudible;
+ }
+
+ return AudioChannelService::AudibleState::eAudible;
}
bool
IsPlayingThroughTheAudioChannel() const
{
// If we have an error, we are not playing.
if (mOwner->GetError()) {
return false;
@@ -1059,18 +1059,18 @@ private:
// It's used to reduce the power consumption, we won't play the auto-play
// audio/video in the page we have never visited before. MediaElement would
// be resumed when the page is active. See bug647429 for more details.
// - SUSPENDED_STOP_DISPOSABLE
// When we permanently lost platform audio focus, we should stop playing
// and stop the audio channel agent. MediaElement can only be restarted by
// play().
SuspendTypes mSuspended;
- // True if media element is audible for users.
- bool mIsOwnerAudible;
+ // Indicate whether media element is audible for users.
+ AudibleState mIsOwnerAudible;
bool mIsShutDown;
};
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMediaElement::AudioChannelAgentCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLMediaElement::AudioChannelAgentCallback)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelAgent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -6971,17 +6971,22 @@ HTMLMediaElement::ShouldElementBePaused(
}
return false;
}
void
HTMLMediaElement::SetMediaInfo(const MediaInfo& aInfo)
{
+ const bool oldHasAudio = mMediaInfo.HasAudio();
mMediaInfo = aInfo;
+ if (aInfo.HasAudio() != oldHasAudio) {
+ NotifyAudioPlaybackChanged(
+ AudioChannelService::AudibleChangedReasons::eDataAudibleChanged);
+ }
if (mAudioChannelWrapper) {
mAudioChannelWrapper->AudioCaptureStreamChangeIfNeeded();
}
}
void
HTMLMediaElement::AudioCaptureStreamChange(bool aCapture)
{
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -33,16 +33,17 @@
// Define to output information on decoding and painting framerate
/* #define DEBUG_FRAME_RATE 1 */
typedef uint16_t nsMediaNetworkState;
typedef uint16_t nsMediaReadyState;
typedef uint32_t SuspendTypes;
typedef uint32_t AudibleChangedReasons;
+typedef uint8_t AudibleState;
namespace mozilla {
class DecoderDoctorDiagnostics;
class DOMMediaStream;
class ErrorResult;
class MediaResource;
class MediaDecoder;
class VideoFrameContainer;