Bug 1016277 - Telephony AudioChannel policy: LIFO r=mchen

--HG--
rename : dom/base/test/audio.ogg => dom/audiochannel/tests/audio.ogg
This commit is contained in:
Andrea Marchesini 2014-07-10 15:06:23 +02:00
parent 42cda37bac
commit 187ed14a21
6 changed files with 212 additions and 11 deletions

View File

@ -151,6 +151,13 @@ AudioChannelService::RegisterType(AudioChannel aChannel, uint64_t aChildID,
mChannelCounters[type].AppendElement(aChildID);
if (XRE_GetProcessType() == GeckoProcessType_Default) {
// We must keep the childIds in order to decide which app is allowed to play
// with then telephony channel.
if (aChannel == AudioChannel::Telephony) {
RegisterTelephonyChild(aChildID);
}
// Since there is another telephony registered, we can unregister old one
// immediately.
if (mDeferTelChannelTimer && aChannel == AudioChannel::Telephony) {
@ -234,15 +241,21 @@ AudioChannelService::UnregisterType(AudioChannel aChannel,
// There are two reasons to defer the decrease of telephony channel.
// 1. User can have time to remove device from his ear before music resuming.
// 2. Give BT SCO to be disconnected before starting to connect A2DP.
if (XRE_GetProcessType() == GeckoProcessType_Default &&
aChannel == AudioChannel::Telephony &&
(mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
mTimerElementHidden = aElementHidden;
mTimerChildID = aChildID;
mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
return;
if (XRE_GetProcessType() == GeckoProcessType_Default) {
if (aChannel == AudioChannel::Telephony) {
UnregisterTelephonyChild(aChildID);
}
if (aChannel == AudioChannel::Telephony &&
(mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
mTimerElementHidden = aElementHidden;
mTimerChildID = aChildID;
mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
return;
}
}
UnregisterTypeInternal(aChannel, aElementHidden, aChildID, aWithVideo);
@ -358,7 +371,7 @@ AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
if (CheckVolumeFadedCondition(newType, aElementHidden)) {
return AUDIO_CHANNEL_STATE_FADED;
}
return AUDIO_CHANNEL_STATE_NORMAL;
return CheckTelephonyPolicy(aChannel, aChildID);
}
// We are not visible, maybe we have to mute.
@ -387,7 +400,34 @@ AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
return AUDIO_CHANNEL_STATE_MUTED;
}
return AUDIO_CHANNEL_STATE_NORMAL;
return CheckTelephonyPolicy(aChannel, aChildID);
}
AudioChannelState
AudioChannelService::CheckTelephonyPolicy(AudioChannel aChannel,
uint64_t aChildID)
{
// Only the latest childID is allowed to play with telephony channel.
if (aChannel != AudioChannel::Telephony) {
return AUDIO_CHANNEL_STATE_NORMAL;
}
MOZ_ASSERT(!mTelephonyChildren.IsEmpty());
#if DEBUG
bool found = false;
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
if (mTelephonyChildren[i].mChildID == aChildID) {
found = true;
break;
}
}
MOZ_ASSERT(found);
#endif
return mTelephonyChildren.LastElement().mChildID == aChildID
? AUDIO_CHANNEL_STATE_NORMAL : AUDIO_CHANNEL_STATE_MUTED;
}
bool
@ -986,3 +1026,39 @@ AudioChannelService::GetDefaultAudioChannelString(nsAString& aString)
}
}
}
void
AudioChannelService::RegisterTelephonyChild(uint64_t aChildID)
{
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
if (mTelephonyChildren[i].mChildID == aChildID) {
++mTelephonyChildren[i].mInstances;
if (i != len - 1) {
TelephonyChild child = mTelephonyChildren[i];
mTelephonyChildren.RemoveElementAt(i);
mTelephonyChildren.AppendElement(child);
}
return;
}
}
mTelephonyChildren.AppendElement(TelephonyChild(aChildID));
}
void
AudioChannelService::UnregisterTelephonyChild(uint64_t aChildID)
{
for (uint32_t i = 0, len = mTelephonyChildren.Length(); i < len; ++i) {
if (mTelephonyChildren[i].mChildID == aChildID) {
if (!--mTelephonyChildren[i].mInstances) {
mTelephonyChildren.RemoveElementAt(i);
}
return;
}
}
MOZ_ASSERT(false, "This should not happen.");
}

View File

@ -150,6 +150,11 @@ protected:
void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
bool aHidden, uint64_t aChildID);
AudioChannelState CheckTelephonyPolicy(AudioChannel aChannel,
uint64_t aChildID);
void RegisterTelephonyChild(uint64_t aChildID);
void UnregisterTelephonyChild(uint64_t aChildID);
AudioChannelService();
virtual ~AudioChannelService();
@ -225,6 +230,19 @@ protected:
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:

Binary file not shown.

View 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>

View File

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

View File

@ -0,0 +1,85 @@
<!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.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();
runTest();
</script>
</body>
</html>