diff --git a/scripts/caption.js b/scripts/caption.js
index e2878d19..2b85923c 100644
--- a/scripts/caption.js
+++ b/scripts/caption.js
@@ -197,7 +197,13 @@
if (this.currentCaption !== thisCaption) {
// it's time to load the new caption into the container div
captionText = this.flattenCueForCaption(cues[thisCaption]).replace( /\n/g, "
" );
-
+ // If preference enabled to voice captions, send to synthesizer.
+ if ( this.speechEnabled && this.prefCaptionsSpeak ) {
+ let announceText = new DOMParser().parseFromString( captionText, 'text/html' );
+ let announcement = announceText.body.textContent || '';
+ // use browser's built-in speech synthesis
+ this.announceText( 'caption', announcement );
+ }
this.$captionsDiv.html(captionText);
this.currentCaption = thisCaption;
if (captionText.length === 0) {
@@ -323,7 +329,29 @@
options[0] = "overlay";
options[1] = "below";
break;
+
+ case "prefCaptionsSpeak":
+ options[0] = ["0", this.translate( 'off', 'Off' ) ];
+ options[1] = ["1", this.translate( 'on', 'On' ) ];
+ break;
+
+ case "prefCaptionsVoice":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsPitch":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsRate":
+ options[0] = null; // set later.
+ break;
+
+ case "prefCaptionsVolume":
+ options[0] = null; // set later.
+ break;
}
+
return options;
};
diff --git a/scripts/description.js b/scripts/description.js
index 871b7abc..aafe589d 100644
--- a/scripts/description.js
+++ b/scripts/description.js
@@ -238,7 +238,7 @@
var preferences, voices, prefDescVoice, descVoice, descLang, prefVoiceFound;
preferences = this.getPref();
- prefDescVoice = (typeof preferences.voices !== 'undefined') ? this.getPrefDescVoice() : null;
+ prefDescVoice = (typeof preferences.voices !== 'undefined') ? this.getPrefVoice() : null;
this.getBrowserVoices();
this.rebuildDescPrefsForm();
@@ -488,7 +488,7 @@
} else if (this.speechEnabled) {
if ( 'video' !== this.descMethod ) {
// use browser's built-in speech synthesis
- this.announceDescriptionText('description',descText);
+ this.announceText('description',descText);
}
if (this.prefDescVisible) {
// write description to the screen for sighted users
@@ -543,13 +543,14 @@
this.prefDescRate = speechRate;
};
- AblePlayer.prototype.announceDescriptionText = function(context, text) {
+ AblePlayer.prototype.announceText = function(context, text) {
- // this function announces description text using speech synthesis
+ // this function announces text using speech synthesis
// it's only called if already determined that browser supports speech synthesis
// context is either:
// 'description' - actual description text extracted from WebVTT file
// 'sample' - called when user changes a setting in Description Prefs dialog
+ // 'caption' - called when announcing a caption.
var thisObj, voiceName, i, voice, pitch, rate, volume, utterance,
timeElapsed, secondsElapsed;
@@ -586,12 +587,24 @@
pitch = $('#' + this.mediaId + '_prefDescPitch').val();
rate = $('#' + this.mediaId + '_prefDescRate').val();
volume = $('#' + this.mediaId + '_prefDescVolume').val();
- } else {
+ } else if ( context === 'captionSample' ) {
+ // get settings from form
+ voiceName = $('#' + this.mediaId + '_prefCaptionsVoice').val();
+ pitch = $('#' + this.mediaId + '_prefCaptionsPitch').val();
+ rate = $('#' + this.mediaId + '_prefCaptionsRate').val();
+ volume = $('#' + this.mediaId + '_prefCaptionsVolume').val();
+ } else if ( context === 'description' ) {
// get settings from global prefs
voiceName = this.prefDescVoice;
pitch = this.prefDescPitch;
rate = this.prefDescRate;
volume = this.prefDescVolume;
+ } else {
+ // get settings from global prefs
+ voiceName = this.prefCaptionsVoice;
+ pitch = this.prefCaptionsPitch;
+ rate = this.prefCaptionsRate;
+ volume = this.prefCaptionsVolume;
}
// get the voice associated with the user's chosen voice name
diff --git a/scripts/preference.js b/scripts/preference.js
index a03a16ff..f0bbc6ca 100644
--- a/scripts/preference.js
+++ b/scripts/preference.js
@@ -239,6 +239,36 @@
'group': 'captions',
'default': '100%'
});
+ prefs.push({
+ 'name': 'prefCaptionsSpeak',
+ 'label': this.translate( 'prefVoicedCaptions', 'Voiced Captions' ),
+ 'group': 'captions',
+ 'default': 0
+ });
+ prefs.push({
+ 'name': 'prefCaptionsVoice',
+ 'label': this.translate( 'prefDescVoice', 'Voice' ),
+ 'group': 'captions',
+ 'default': null // will be set later, in injectPrefsForm()
+ });
+ prefs.push({
+ 'name': 'prefCaptionsPitch',
+ 'label': this.translate( 'prefDescPitch', 'Pitch' ),
+ 'group': 'captions',
+ 'default': 1 // 0 to 2
+ });
+ prefs.push({
+ 'name': 'prefCaptionsRate',
+ 'label': this.translate( 'prefDescRate', 'Rate' ),
+ 'group': 'captions',
+ 'default': 1.2 // 0.1 to 10 (1 is normal speech; 2 is fast but decipherable; >2 is super fast)
+ });
+ prefs.push({
+ 'name': 'prefCaptionsVolume',
+ 'label': this.translate( 'volume', 'Volume' ),
+ 'group': 'captions',
+ 'default': 1 // 0 to 1
+ });
}
if (this.mediaType === 'video') {
@@ -340,7 +370,7 @@
var thisObj, available,
$prefsDiv, formTitle, introText, $prefsIntro,$prefsIntroP2,p3Text,$prefsIntroP3,i, j,
$fieldset, fieldsetClass, fieldsetId, $legend, legendId, thisPref, $thisDiv, thisClass,
- thisId, $thisLabel, $thisField, options,$thisOption,optionValue,optionLang,optionText,
+ thisId, $thisLabel, $thisField, captionsOptions,options,$thisOption,optionValue,optionLang,optionText,
changedPref,changedSpan,changedText, currentDescState, prefDescVoice, $kbHeading,$kbList,
kbLabels,keys,kbListText,$kbListItem, dialog,$saveButton,$cancelButton,$buttonContainer;
@@ -434,7 +464,7 @@
thisPref = available[i]['name'];
thisClass = 'able-' + thisPref;
thisId = this.mediaId + '_' + thisPref;
- $thisDiv = $('
').addClass(thisClass);
+ $thisDiv = $('
').addClass(thisClass + ' able-player-setting');
if (form === 'captions') {
$thisLabel = $('');
@@ -442,44 +472,97 @@
name: thisPref,
id: thisId,
});
- if (thisPref !== 'prefCaptions' && thisPref !== 'prefCaptionsStyle') {
- // add a change handler that updates the style of the sample caption text
+ // add a change handler that updates the style of the sample caption text
+ let viewingOptions = ['prefCaptionsPosition','prefCaptionsFont','prefCaptionsSize','prefCaptionsColor','prefCaptionsBGColor','prefCaptionsOpacity'];
+ if ( viewingOptions.indexOf(thisPref) !== -1 ) {
$thisField.on( 'change', function() {
changedPref = $(this).attr('name');
thisObj.stylizeCaptions(thisObj.$sampleCapsDiv,changedPref);
});
}
- options = this.getCaptionsOptions(thisPref);
- for (j=0; j < options.length; j++) {
+ captionsOptions = this.getCaptionsOptions(thisPref);
+ $thisDiv.append($thisLabel,$thisField);
+ for (j=0; j < captionsOptions.length; j++) {
if (thisPref === 'prefCaptionsPosition') {
- optionValue = options[j];
+ optionValue = captionsOptions[j];
if (optionValue === 'overlay') {
optionText = this.translate( 'captionsPositionOverlay', 'Overlay' );
} else if (optionValue === 'below') {
- optionValue = options[j];
+ optionValue = captionsOptions[j];
optionText = this.translate( 'captionsPositionBelow', 'Below video' );
}
- } else if (thisPref === 'prefCaptionsFont' || thisPref === 'prefCaptionsColor' || thisPref === 'prefCaptionsBGColor') {
- optionValue = options[j][0];
- optionText = options[j][1];
+ } else if (thisPref === 'prefCaptionsFont' || thisPref === 'prefCaptionsColor' || thisPref === 'prefCaptionsBGColor' || thisPref === 'prefCaptionsSpeak' ) {
+ optionValue = captionsOptions[j][0];
+ optionText = captionsOptions[j][1];
} else if (thisPref === 'prefCaptionsOpacity') {
- optionValue = options[j];
- optionText = options[j];
+ optionValue = captionsOptions[j];
+ optionText = captionsOptions[j];
optionText += (optionValue === '0%') ? ' (' + this.translate( 'transparent', 'transparent' ) + ')' : ' (' + this.translate( 'solid', 'solid' ) + ')';
- } else {
- optionValue = options[j];
- optionText = options[j];
+ } else if (thisPref === 'prefCaptionsSize') {
+ optionValue = captionsOptions[j];
+ optionText = captionsOptions[j];
}
- $thisOption = $('