-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preloading of audio and bandwidth confirmation #3727
Conversation
tjiang11
commented
Aug 9, 2017
- Users are asked to confirm bandwidth usage when trying to download audio
- Audio is loaded and cached after confirming bandwidth usage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @tjiang11! This looks pretty solid technically, but I have some questions about the intended UX.
@@ -121,6 +121,18 @@ oppia.factory('StatesObjectFactory', [ | |||
return allAudioLanguageCodes; | |||
}; | |||
|
|||
States.prototype.getAllAudioTranslations = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember to write tests, please :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -17,11 +17,11 @@ states: | |||
audio_translations: | |||
en: | |||
filename: 'test_audio_2_en.mp3' | |||
file_size_bytes: 2 | |||
file_size_bytes: 100 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using the actual values for the files (59 in this case; ditto below). (I noticed this when trying to do a sanity check of the 1.13 MB.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah sorry I kept thinking in kB when we were using bytes so these values were way too low, using actual values now
'ExplorationPlayerStateService', 'UrlInterpolationService', | ||
function($modal, explorationContextService, AssetsBackendApiService, | ||
ExplorationPlayerStateService, UrlInterpolationService) { | ||
var NUM_BYTES_IN_MB = 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, there are (1 << 20)
bytes in an MB...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
// and subsequently for confirmation to use bandwidth | ||
// to download audio files. | ||
if (!AudioPreloaderService.hasPreloaded()) { | ||
if (getCurrentAudioTranslation()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what circumstance does this condition evaluate to true? I get this popup modal as soon as I try to play any one file...
Also, I have a general question about this. The options available to me as a learner seem to be preload-or-nothing, and the former option downloads all the audio in the entire exploration. Do I not get the option to just download the specific audio files I need on an as-needed basis? (I looked at the doc, but I'm not sure that this part was written out in detail...or maybe I misunderstood it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should evaluate to true if there is an audio translation available in the current language.
Yeah, I assumed learners would either be willing to use the necessary bandwidth for all audio or decline to use any bandwidth. But I suppose there is a middleground where some learners may need help with only one specific piece of content and also be restrictive in their use of bandwidth.
Yeah sorry, it was never in the design doc. How about this: clicking "continue" will only download the current file. But a checkbox will also be present saying "Download all audio for this exploration (XX MB)". And preloading will occur only if the learner checks that. Does that sound okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, interesting. On reading I had interpreted "getCurrentAudioTranslation()" as "get the audio translation that's currently playing". I wonder if we could change the name to make the intended meaning clearer...
And yep that sounds good! In the non-preload case, what about subsequent downloads, though? Will there be a modal each time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If they preloaded, then there shouldn't be any more modals. But they'll still see modals each time if they decide to only download that specific file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I suppose it'd be better to be extra cautious if they're being restrictive on their bandwidth--?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the function name to getAudioTranslationInCurrentLanguage()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, all this sgtm. Thanks!
var _hasPreloaded = false; | ||
var _excludedFilename = null; | ||
|
||
var _preload = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps _preloadAllAudioFiles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ExplorationPlayerStateService, UrlInterpolationService) { | ||
var NUM_BYTES_IN_MB = 1000; | ||
var _hasPreloaded = false; | ||
var _excludedFilename = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add one-line comments above these. Without context, I don't know what e.g. _excludedFilename refers to or represents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
$scope, $modalInstance, | ||
ExplorationPlayerStateService, AudioPreloaderService) { | ||
$scope.totalFileSizeOfAllAudioTranslationsBytes = | ||
_calculateTotalFileSize( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe define this as a method on the exploration object? (Please add tests too.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}); | ||
}; | ||
|
||
var _calculateTotalFileSize = function(audioTranslations) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit to the function name, e.g. _calculateTotalFileSizeMB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
function( | ||
$scope, $modalInstance, | ||
ExplorationPlayerStateService, AudioPreloaderService) { | ||
$scope.totalFileSizeOfAllAudioTranslationsBytes = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The units in this name seem misleading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to MB
assets/i18n/en.json
Outdated
"I18N_ONE_SUBSCRIBER_TEXT": "You have 1 subscriber.", | ||
"I18N_PLAYER_AUDIO_LANGUAGE": "Language", | ||
"I18N_PLAYER_AUDIO_MIGHT_NOT_MATCH_TEXT": "Audio might not fully match text", | ||
"I18N_PLAYER_AUDIO_NOT_AVAILABLE_IN": "Not available in <[languageDescription]>", | ||
"I18N_PLAYER_AUDIO_TRANSLATION_SETTINGS": "Audio Translation Settings", | ||
"I18N_PLAYER_BACK": "Back", | ||
"I18N_PLAYER_BACK_TO_COLLECTION": "Back to collection", | ||
"I18N_PLAYER_BANDWIDTH_USAGE_WARNING_MODAL_BODY": "This exploration contains <b><[filesize]>MB</b> of audio. Continue downloading?", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider calling the variable fileSizeMB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Codecov Report
@@ Coverage Diff @@
## develop #3727 +/- ##
===========================================
- Coverage 45.06% 45.04% -0.03%
===========================================
Files 264 265 +1
Lines 20427 20510 +83
Branches 3174 3184 +10
===========================================
+ Hits 9205 9238 +33
- Misses 11222 11272 +50
Continue to review full report at Codecov.
|
// Whether all audio files have been preloaded in the exploration. | ||
var _hasPreloaded = false; | ||
|
||
// This is a file to exclude while preloading all audio translations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought: if you're supporting the "load each file individually" case, should you be maintaining a list of exclusions here instead? Maybe exposing a markFileAsAlreadyLoaded() function would be a way to do this, but if there's some way we could do something like getAlreadyLoadedFiles() from the audio caching service then that might be even better since we don't have to keep track of this in multiple places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like it shouldn't make a difference, because AssetsBackendApiService already maintains its own cache, and AudioPreloaderService just fills up the cache with any audio that hasn't been loaded yet. If a file is already in the cache, it won't be fetched for again via the check in AssetsBackendApiService.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, OK. So do we even need _excludedFilename then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the reason why I had to put that was because otherwise there are two simultaneous requests for the same file, so AssetsBackendApiService can't use the cache check. Thinking about it more though, if the bandwidth is low enough, it might be the case that a learner might go on to another audio while it's still in the process of preloading. So maybe AssetsBackendApiService could maintain a list of files currently being preloaded?
(don't review this yet) |
Ready for another pass @seanlip |
Going to be adding some more comments shortly, since I realized it's rather windy.. |
assets/i18n/qqq.json
Outdated
"I18N_ONE_SUBSCRIBER_TEXT": "Text displayed under the subscribers tab in creator dashboard. If the creator has one subscriber, this text is displayed which informs him/her about the same.", | ||
"I18N_PLAYER_AUDIO_LANGUAGE": "Text displayed in the audio translation settings modal, asking the learner to pick what language they want to listen to audio translations in.", | ||
"I18N_PLAYER_AUDIO_MIGHT_NOT_MATCH_TEXT": "Text displayed under the audio controls to the learner when the audio translation for the current language is flagged as needing an update by the creator.", | ||
"I18N_PLAYER_AUDIO_NOT_AVAILABLE_IN": "Text displayed in a tooltip over the speaker icon to play audio when there is no audio available in the selected language.", | ||
"I18N_PLAYER_AUDIO_TRANSLATION_SETTINGS": "Title displayed at the top of the audio translation settings modal in the learner view.", | ||
"I18N_PLAYER_BACK": "Text read to users with screenreaders when they navigate through an exploration. - This labels the leftward-pointing arrow that is used to go backward by one card in the exploration.\n{{Identical|Back}}", | ||
"I18N_PLAYER_BACK_TO_COLLECTION": "Text shown to users after they complete an exploration in a collection. - This labels the link that is used to return back to the home page of the collection the user is currently exploring", | ||
"I18N_PLAYER_BANDWIDTH_USAGE_WARNING_MODAL_BODY": "Text displayed in the body of the modal shown when the user clicks to play audio for the first time asking if they would like to use bandwidth to download audio.", | ||
"I18N_PLAYER_BANDWIDTH_USAGE_WARNING_MODAL_DOWNLOAD_ALL_AUDIO": "Text displayed by the checkbox of the modal shown when the user clicks to play audio for the first time asking if they would like to use bandwidth to download audio. Checking the assoicated checkbox signifies that the user intends to predownload all audio translation in the exploration of the selected language.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
predownload all audio translations ... (pluralize "translations")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
var allAudioTranslations = | ||
this.states.getAllAudioTranslations(languageCode); | ||
allAudioTranslations.map(function(audioTranslation) { | ||
totalFileSizeBytes += audioTranslation.fileSizeBytes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: Might as well reuse audioTranslation.getFileSizeMB()? At the very least you don't then duplicate NUM_BYTES_IN_MB across the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -86,7 +106,7 @@ oppia.directive('audioControls', [ | |||
// immediately start playing the newly requested audio. | |||
loadAndPlayAudioTranslation(); | |||
} | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove trailing whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
if (!AudioPreloaderService.hasPreloadedLanguage( | ||
getCurrentAudioLanguageCode()) && | ||
!isCached(audioTranslation)) { | ||
AudioPreloaderService.excludeFile( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm ... I don't really see why the audio controls directive cares about all these details. Shouldn't the preloader (or even the backend api service) handle it internally? I assume the issue is that the current translation is in the middle of being loaded, but presumably the backend api service could maintain some sort of list detailing which requests are currently in flight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, yeah that's what I suggested in the earlier lost comment--will add that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
function($modal, explorationContextService, AssetsBackendApiService, | ||
ExplorationPlayerStateService, UrlInterpolationService, | ||
AudioTranslationManagerService) { | ||
// Mapping from language code to boolean indicating if it has |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an array rather than a mapping to me...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
…to prevent duplicate requests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks @tjiang11!
* upstream/develop: (28 commits) Preloading of audio and bandwidth confirmation (oppia#3727) Fix oppia#3693: Deprecate ClassifierDataModel and update ClassifierTrainingJobModel (oppia#3734) Fix part of oppia#3453: Removed jinja template in editor_navigation_directive (oppia#3732) Eliminates stray tick mark (oppia#3731) Fix oppia#3453: Removed jinja template in collection editor navigation bar directive (oppia#3723) Fix oppia#3726: prevent graph SVG from overlapping modal footer buttons. (oppia#3728) address sean review comments Add a one-off job to list which explorations use gadgets; remove old fallbacks job. (oppia#3717) fix linting remove jinja template in create_activity_modal Fix oppia#2998 implement collection skills update commands (oppia#3710) Improvements and bug fixes to changes introduced by PR oppia#3671 (oppia#3684) Fix oppia#3688: refactoring ExplorationStatusHandler to remove unpublish and publicize functionality as it is not called from frontend. (oppia#3715) fix oppia#3698: Shift exception handling for NotLoggedInException so that it does not generate log errors. (oppia#3714) Revert "Fix oppia#3707 Change text of collection learner view "start here"" (oppia#3713) Fix oppia#3701 Fixed Continue button name issue (oppia#3711) Fix oppia#3467: Introduce re-training and add_to_training_queue methods (oppia#3650) Fix oppia#3707 Change text of collection learner view "start here" (oppia#3700) Audio fixes: make audio download URL safe; don't show flagging modal if all translations are flagged; use templateUrl for modals. (oppia#3709) Learner audio updates (oppia#3705) ...
* upstream/develop: fix variable name Preloading of audio and bandwidth confirmation (oppia#3727) Fix oppia#3693: Deprecate ClassifierDataModel and update ClassifierTrainingJobModel (oppia#3734) Fix part of oppia#3453: Removed jinja template in editor_navigation_directive (oppia#3732) use userIsLoggedIn instead of hasFullyRegistered variable address Sean review comments remove new line removed jinja template logics in search_results_directive Eliminates stray tick mark (oppia#3731) Fix oppia#3453: Removed jinja template in collection editor navigation bar directive (oppia#3723) Fix oppia#3726: prevent graph SVG from overlapping modal footer buttons. (oppia#3728) address sean review comments fix linting remove jinja template in create_activity_modal