All files / Player/Streams createManifestRotationStream.js

100% Statements 40/40
83.33% Branches 10/12
100% Functions 6/6
100% Lines 37/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 961x                 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x                 1x         4x   2x 8x 2x 2x 2x   18x 2x 2x         2x 18x 18x 6x 6x 6x   18x 2x       2x 2x     16x     2x 2x   2x   2x           18x                                  
import {
    map,
    mapTo,
    filter,
    startWith,
    tap,
    switchMap,
    takeUntil,
} from 'rxjs/operators';
import { Subject, from, merge } from 'rxjs';
import once from 'ramda/src/once';
 
import { RETRY_COUNT_CDN_ROTATION }                     from '../../Errors/Constants/Error.retries';
import ErrorType                                        from '../../Errors/Constants/Error.type';
import memoizeConnection                                from '../../Shared/Utils/memoizeConnection';
import { isStartupError }                               from '../Utils/cdnErrorFilters';
import { mapResumeFromToCurrentTime, extractLoadData }  from '../Utils/extractLoadData';
import manifestsGenerator                               from '../Utils/manifestsGenerator';
import createExcessiveBufferingStream                   from './createExcessiveBufferingStream';
import createRotationErrorsStream                       from './createRotationErrorsStream';
 
/**
 * @param  {playback-web-player.PlayerFacade} player
 * @param  {ErrorsHandler.handleError} handleError
 * @param  {[Playback, ResumePoints, Config, Asset]} loadData
 * @param  {Number} maxRetries
 */
 
const createManifestRotationStream = (
    player,
    handleError,
    loadData,
    maxRetries = RETRY_COUNT_CDN_ROTATION,
) => {
    const [{ manifests }] = loadData;
    const errorNotifier$ = new Subject();
    const createManifestGenerator = () => manifestsGenerator(manifests);
    let manifestGen = createManifestGenerator();
    let retries = 0;
    let errorType = null;
 
    const getErrorType = () => errorType;
    const setErrorType = error => {
        errorType = isStartupError(error)
            ? ErrorType.PLAYBACK_SOURCE_STARTUP
            : ErrorType.PLAYBACK_SOURCE_MIDSTREAM;
    };
 
    const mapToNextManifest = () => {
        let nextManifest = manifestGen.next().value;
        if (!nextManifest && (retries <= maxRetries)) {
            retries++;
            manifestGen = createManifestGenerator();
            nextManifest = manifestGen.next().value;
        }
        if (retries > maxRetries) {
            handleError({
                type: getErrorType(),
                source: loadData,
            });
            errorNotifier$.next();
            return void 0;
        }
 
        return nextManifest;
    };
 
    const rotationErrors$ = createRotationErrorsStream(player.errors$, errorNotifier$);
    const excessiveBuffering$ = createExcessiveBufferingStream(player.state.stores.playback.update$);
 
    const getIsConnectionOk = memoizeConnection();
 
    return merge(
        rotationErrors$,
        excessiveBuffering$,
    )
        .pipe(
            takeUntil(errorNotifier$),
            switchMap(error =>
                from(getIsConnectionOk())
                    .pipe(
                        filter(Boolean),
                        mapTo(error)
                    )
            ),
            tap(once(setErrorType)),
            map(mapToNextManifest),
            filter(Boolean),
            map(extractLoadData.bind(null, loadData)),
            map(mapResumeFromToCurrentTime.bind(null, getErrorType, player)),
            startWith(extractLoadData(loadData, manifestGen.next().value)),
        );
};
 
export default createManifestRotationStream;