/* global BaseModule */
'use strict';
(function() {
// The results of audo channel competition.
var PLAY = true;
var PAUSE = false;
/**
* It is the table to get the result of
* the competition of audio channels.
*
* Get the result of the competition
* of normal and content audio channels with
* `AUDIO_CHANNEL_COMPETITION_RESULTS.normal.content`.
*/
var AUDIO_CHANNEL_COMPETITION_RESULTS = {
normal: {
normal: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
content: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
content: {
normal: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
content: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
alarm: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
system: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
ringer: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PAUSE, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
telephony: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PLAY, newAudioChannel: PAUSE },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PLAY, newAudioChannel: PAUSE },
notification: { activeAudioChannel: PLAY, newAudioChannel: PAUSE },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
notification: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
},
publicNotification: {
normal: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
content: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
alarm: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
system: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
ringer: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
telephony: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
notification: { activeAudioChannel: PLAY, newAudioChannel: PLAY },
publicNotification: { activeAudioChannel: PLAY, newAudioChannel: PLAY }
}
};
/**
* AudioChannelPolicy provides policies to handle audio channels.
*/
var AudioChannelPolicy = function() {};
AudioChannelPolicy.SETTINGS = [
'vibration.enabled'
];
BaseModule.create(AudioChannelPolicy, {
name: 'AudioChannelPolicy',
DEBUG: false,
// The value of the vibration.enabled settings.
_isVibrateEnabled: true,
/**
* Get the policies of
* handling the new audio channel and active audio channels.
*
* @param {AudioChannelController} newAudioChannel
* A new audio channel you want to handle.
* @param {Map} activeAudioChannels
* Active audio channels playing noew.
* @param {Object} [options] Options.
* @param {Boolean} [options.isNewAudioChannelInBackground]
* Is the new audio channel in background.
*/
applyPolicy: function(newAudioChannel, activeAudioChannels, options) {
var newAudioChannelName = newAudioChannel.name;
// Deconflict the conflicted policies for the new audio channel.
// For example, we have a new audio channel `alarm` and
// two active audio channels `system` and `telephony`.
// `AUDIO_CHANNEL_COMPETITION_RESULTS.system.alarm` is `true`,
// but `AUDIO_CHANNEL_COMPETITION_RESULTS.telephony.alarm`
// is `false`.
// And we get conflict policies for the `alarm` audio channel.
// Once we get conflcts, we will take higher priority policy.
// `PAUSE` is higher than `PLAY`,
// and doing fade out is higher than not doing fade out.
var isAllowedToPlayForNewAudioChannel = [true];
var isNeededToFadeOutForNewAudioChannel = [false];
// The new audio channel will be allowed to play,
// if any other audio channel belonged to its app is already playing.
var isNewAudioChannelsAppPlaying = false;
activeAudioChannels.forEach((audioChannel) => {
if (audioChannel.app.instanceID === newAudioChannel.app.instanceID) {
isNewAudioChannelsAppPlaying = true;
}
});
!isNewAudioChannelsAppPlaying &&
activeAudioChannels.forEach((audioChannel) => {
var activeAudioChannelName = audioChannel.name;
var results = AUDIO_CHANNEL_COMPETITION_RESULTS
[activeAudioChannelName][newAudioChannelName];
var policy = {
isAllowedToPlay: results.activeAudioChannel
};
if (results.activeAudioChannel) {
policy.isNeededToFadeOut =
this._isNeededToFadeOutForActiveAudioChannel(
activeAudioChannelName, newAudioChannelName
);
}
if (!results.activeAudioChannel) {
policy.isNeededToVibrate = this._isVibrateEnabled &&
this._isNeededToVibrateForActiveAudioChannel(
activeAudioChannelName, newAudioChannelName
);
policy.isNeededToResumeWhenOtherEnds =
this._isNeededToResumeWhenOtherEndsForActiveAudioChannel(
activeAudioChannelName, newAudioChannelName
);
}
audioChannel.setPolicy(policy);
this.debug('Policy for ' + audioChannel.instanceID +
': ' + JSON.stringify(policy));
isAllowedToPlayForNewAudioChannel.push(results.newAudioChannel);
results.newAudioChannel && isNeededToFadeOutForNewAudioChannel.push(
this._isNeededToFadeOutForNewAudioChannel
(activeAudioChannelName, newAudioChannelName)
);
});
// Normal channel could not play in background.
if (newAudioChannelName === 'normal' &&
options && options.isNewAudioChannelInBackground) {
isAllowedToPlayForNewAudioChannel.push(false);
}
// Deconflict the policies.
isAllowedToPlayForNewAudioChannel =
isAllowedToPlayForNewAudioChannel.every(isAllowed => isAllowed);
isNeededToFadeOutForNewAudioChannel =
isNeededToFadeOutForNewAudioChannel.some(isNeeded => isNeeded);
var policy = {
isAllowedToPlay: isAllowedToPlayForNewAudioChannel
};
if (isAllowedToPlayForNewAudioChannel) {
policy.isNeededToFadeOut = isNeededToFadeOutForNewAudioChannel;
}
if (!isAllowedToPlayForNewAudioChannel) {
policy.isNeededToVibrate = this._isVibrateEnabled &&
!isAllowedToPlayForNewAudioChannel &&
// Don't vibrate for background normal audio channel.
newAudioChannelName !== 'normal';
}
newAudioChannel.setPolicy(policy);
this.debug('Policy for ' + newAudioChannel.instanceID +
': ' + JSON.stringify(policy));
},
/**
* Observer the value of vibration.enabled settings.
*
* @param {Boolean} value The value of the settings.
*/
'_observe_vibration.enabled': function(value) {
this._isVibrateEnabled = value;
},
/**
* Get the policy of fading out the new audio channel.
*
* @param {String} activeChannelName The active audio channel name.
* @param {String} newChannelName The new audio channel name.
* @return {Boolean}
*/
_isNeededToFadeOutForNewAudioChannel:
function(activeChannelName, newChannelName) {
var isNeeded = false;
if ((activeChannelName === 'notification' ||
activeChannelName === 'publicNotification') &&
(newChannelName === 'normal' ||
newChannelName === 'content')
)
{
isNeeded = true;
}
return isNeeded;
},
/**
* Get the policy of fading out the active audio channel.
*
* @param {String} activeChannelName The active audio channel name.
* @param {String} newChannelName The new audio channel name.
* @return {Boolean}
*/
_isNeededToFadeOutForActiveAudioChannel:
function(activeChannelName, newChannelName) {
var isNeeded = false;
if (((activeChannelName === 'normal' ||
activeChannelName === 'content') &&
(newChannelName === 'notification' ||
newChannelName === 'publicNotification')
) ||
(activeChannelName === 'alarm' &&
(newChannelName === 'ringer' ||
newChannelName === 'telephony')
)
)
{
isNeeded = true;
}
return isNeeded;
},
/**
* Get the policy of vibrating for the active audio channel.
*
* @param {String} activeChannelName The active audio channel name.
* @param {String} newChannelName The new audio channel name.
* @return {Boolean}
*/
_isNeededToVibrateForActiveAudioChannel:
function(activeChannelName, newChannelName) {
return activeChannelName === 'ringer' && newChannelName === 'ringer';
},
/**
* Get the policy of resuming the active audio channel
* when any other audio channel ends.
*
* @param {String} activeChannelName The active audio channel name.
* @param {String} newChannelName The new audio channel name.
* @return {Boolean}
*/
_isNeededToResumeWhenOtherEndsForActiveAudioChannel:
function(activeChannelName, newChannelName) {
var isNeeded = true;
if (activeChannelName === 'normal' ||
(activeChannelName === 'content' && newChannelName === 'normal') ||
(activeChannelName === 'alarm' && newChannelName === 'alarm') ||
(activeChannelName === 'ringer' && newChannelName === 'ringer')) {
isNeeded = false;
}
return isNeeded;
}
});
}());