aboutsummaryrefslogtreecommitdiffstats
path: root/src/js/support.js
blob: 9b5d2aa040353ec083d167b68d7c72fba87991e6 (plain)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// ==========================================================================
// Plyr support checks
// ==========================================================================

import { transitionEndEvent } from './utils/animation';
import browser from './utils/browser';
import { createElement } from './utils/elements';
import is from './utils/is';

// Default codecs for checking mimetype support
const defaultCodecs = {
  'audio/ogg': 'vorbis',
  'audio/wav': '1',
  'video/webm': 'vp8, vorbis',
  'video/mp4': 'avc1.42E01E, mp4a.40.2',
  'video/ogg': 'theora',
};

// Check for feature support
const support = {
  // Basic support
  audio: 'canPlayType' in document.createElement('audio'),
  video: 'canPlayType' in document.createElement('video'),

  // Check for support
  // Basic functionality vs full UI
  check(type, provider, playsinline) {
    const canPlayInline = browser.isIPhone && playsinline && support.playsinline;
    const api = support[type] || provider !== 'html5';
    const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline);

    return {
      api,
      ui,
    };
  },

  // Picture-in-picture support
  // Safari & Chrome only currently
  pip: (() => {
    if (browser.isIPhone) {
      return false;
    }

    // Safari
    // https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls
    if (is.function(createElement('video').webkitSetPresentationMode)) {
      return true;
    }

    // Chrome
    // https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture
    if (document.pictureInPictureEnabled && !createElement('video').disablePictureInPicture) {
      return true;
    }

    return false;
  })(),

  // Airplay support
  // Safari only currently
  airplay: is.function(window.WebKitPlaybackTargetAvailabilityEvent),

  // Inline playback support
  // https://webkit.org/blog/6784/new-video-policies-for-ios/
  playsinline: 'playsInline' in document.createElement('video'),

  // Check for mime type support against a player instance
  // Credits: http://diveintohtml5.info/everything.html
  // Related: http://www.leanbackplayer.com/test/h5mt.html
  mime(input) {
    if (is.empty(input)) {
      return false;
    }

    const [mediaType] = input.split('/');
    let type = input;

    // Verify we're using HTML5 and there's no media type mismatch
    if (!this.isHTML5 || mediaType !== this.type) {
      return false;
    }

    // Add codec if required
    if (Object.keys(defaultCodecs).includes(type)) {
      type += `; codecs="${defaultCodecs[input]}"`;
    }

    try {
      return Boolean(type && this.media.canPlayType(type).replace(/no/, ''));
    } catch (_) {
      return false;
    }
  },

  // Check for textTracks support
  textTracks: 'textTracks' in document.createElement('video'),

  // <input type="range"> Sliders
  rangeInput: (() => {
    const range = document.createElement('input');
    range.type = 'range';
    return range.type === 'range';
  })(),

  // Touch
  // NOTE: Remember a device can be mouse + touch enabled so we check on first touch event
  touch: 'ontouchstart' in document.documentElement,

  // Detect transitions support
  transitions: transitionEndEvent !== false,

  // Reduced motion iOS & MacOS setting
  // https://webkit.org/blog/7551/responsive-design-for-motion/
  reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,
};

export default support;