@capgo/capacitor-video-player 8.1.6 → 8.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,6 +29,50 @@ npm install @capgo/capacitor-video-player
29
29
  npx cap sync
30
30
  ```
31
31
 
32
+ ## Supported Features
33
+
34
+ | Feature | iOS | Android | Web |
35
+ | ------------------------------ | --- | ------- | --- |
36
+ | Fullscreen native video player | ✅ | ✅ | ❌ |
37
+ | Embedded web video player | ❌ | ❌ | ✅ |
38
+ | Picture in Picture | ✅ | ✅ | ❌ |
39
+ | Subtitles | ✅ | ✅ | ✅ |
40
+ | DRM-protected playback | ✅ | ✅ | ❌ |
41
+ | Chromecast sender playback | ❌ | ✅ | ❌ |
42
+
43
+ ## Chromecast (Android)
44
+
45
+ Chromecast is supported on Android in fullscreen mode. Enable it with the `chromecast` option. When a Cast session starts, the plugin loads the same media URL on the receiver, keeps the current playback position, and routes play, pause, seek, and timeline controls through the Cast session.
46
+
47
+ ```ts
48
+ await VideoPlayer.initPlayer({
49
+ mode: 'fullscreen',
50
+ playerId: 'main-player',
51
+ url: 'https://example.com/video.m3u8',
52
+ title: 'Video title',
53
+ smallTitle: 'Optional subtitle',
54
+ artwork: 'https://example.com/artwork.jpg',
55
+ chromecast: true,
56
+ showControls: true,
57
+ });
58
+ ```
59
+
60
+ ### Chromecast Options
61
+
62
+ | Option | Type | Default | Description |
63
+ | ------------ | --------- | ------- | ---------------------------------------------------------- |
64
+ | `chromecast` | `boolean` | `true` | Shows the Android Cast button and enables sender playback. |
65
+ | `title` | `string` | `""` | Title shown in the sender controls and receiver metadata. |
66
+ | `smallTitle` | `string` | `""` | Subtitle shown in the sender controls and metadata. |
67
+ | `artwork` | `string` | `""` | Image URL used for Cast metadata and sender Cast artwork. |
68
+
69
+ ### Requirements and Notes
70
+
71
+ - The media URL must be reachable by the Chromecast device, not only by the Android app.
72
+ - Cast support depends on the receiver app and device media support. MP4, HLS, DASH, and SmoothStreaming streams are mapped to Cast-compatible MIME types by the plugin.
73
+ - Widevine DRM metadata is forwarded to the Cast media item. DRM-protected streams may still require a receiver that supports your license server and DRM flow.
74
+ - Request headers used by the Android local player are not automatically available to the Chromecast receiver. Use public URLs, signed URLs, cookies supported by your receiver, or a custom receiver for secured media.
75
+
32
76
  ## API
33
77
 
34
78
  <docgen-index>
@@ -65,7 +65,7 @@ dependencies {
65
65
  implementation 'com.google.android.exoplayer:extension-mediasession:2.19.1'
66
66
  implementation 'com.google.android.exoplayer:exoplayer:2.19.1'
67
67
  implementation 'com.google.android.exoplayer:extension-cast:2.19.1'
68
- implementation 'com.squareup.picasso:picasso:2.8'
68
+ implementation 'com.squareup.picasso:picasso:2.71828'
69
69
  testImplementation "junit:junit:$junitVersion"
70
70
  androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
71
71
  androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
@@ -56,6 +56,8 @@ import com.google.android.exoplayer2.PlaybackParameters;
56
56
  import com.google.android.exoplayer2.Player;
57
57
  import com.google.android.exoplayer2.audio.AudioAttributes;
58
58
  import com.google.android.exoplayer2.ext.cast.CastPlayer;
59
+ import com.google.android.exoplayer2.ext.cast.DefaultMediaItemConverter;
60
+ import com.google.android.exoplayer2.ext.cast.MediaItemConverter;
59
61
  import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
60
62
  import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
61
63
  import com.google.android.exoplayer2.source.MediaSource;
@@ -79,16 +81,21 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
79
81
  import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
80
82
  import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
81
83
  import com.google.android.exoplayer2.util.MimeTypes;
84
+ import com.google.android.gms.cast.MediaInfo;
85
+ import com.google.android.gms.cast.MediaQueueItem;
86
+ import com.google.android.gms.cast.MediaTrack;
82
87
  import com.google.android.gms.cast.framework.CastButtonFactory;
83
88
  import com.google.android.gms.cast.framework.CastContext;
84
89
  import com.google.android.gms.cast.framework.CastState;
85
90
  import com.google.android.gms.cast.framework.CastStateListener;
91
+ import com.google.android.gms.common.images.WebImage;
86
92
  import com.google.android.gms.tasks.OnCompleteListener;
87
93
  import com.google.android.gms.tasks.Task;
88
94
  import java.io.IOException;
89
95
  import java.io.InputStream;
90
96
  import java.net.HttpURLConnection;
91
97
  import java.net.URL;
98
+ import java.util.ArrayList;
92
99
  import java.util.Arrays;
93
100
  import java.util.HashMap;
94
101
  import java.util.List;
@@ -97,6 +104,7 @@ import java.util.Map;
97
104
  import java.util.concurrent.Executor;
98
105
  import java.util.concurrent.Executors;
99
106
  import org.json.JSONException;
107
+ import org.json.JSONObject;
100
108
 
101
109
  public class FullscreenExoPlayerFragment extends Fragment {
102
110
 
@@ -188,7 +196,6 @@ public class FullscreenExoPlayerFragment extends Fragment {
188
196
  private MediaRouteButton mediaRouteButton;
189
197
  private CastContext castContext;
190
198
  private CastPlayer castPlayer;
191
- private MediaItem mediaItem;
192
199
  private MediaRouter mRouter;
193
200
  private MediaRouter.Callback mCallback = new EmptyCallback();
194
201
  private MediaRouteSelector mSelector;
@@ -996,18 +1003,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
996
1003
  mediaSources[0] = mediaSource;
997
1004
  String mimeType = getMimeType(sturi);
998
1005
 
999
- // We get the language label from the language code
1000
- String languageLabel = Locale.forLanguageTag(language).getDisplayLanguage();
1001
- MediaItem.SubtitleConfiguration subConfig = new MediaItem.SubtitleConfiguration.Builder(sturi)
1002
- .setMimeType(mimeType)
1003
- .setUri(sturi)
1004
- .setId(subTitle)
1005
- .setLabel(languageLabel)
1006
- .setRoleFlags(C.ROLE_FLAG_CAPTION)
1007
- .setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
1008
- .setLanguage(language)
1009
- .build();
1010
-
1006
+ MediaItem.SubtitleConfiguration subConfig = buildSubtitleConfiguration(sturi, mimeType);
1011
1007
  SingleSampleMediaSource subtitleSource = new SingleSampleMediaSource.Factory(dataSourceFactory).createMediaSource(
1012
1008
  subConfig,
1013
1009
  C.TIME_UNSET
@@ -1331,7 +1327,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1331
1327
  public void onComplete(Task<CastContext> task) {
1332
1328
  if (task.isSuccessful()) {
1333
1329
  castContext = task.getResult();
1334
- castPlayer = new CastPlayer(castContext);
1330
+ castPlayer = new CastPlayer(castContext, new SubtitleMediaItemConverter());
1335
1331
  mRouter = MediaRouter.getInstance(context);
1336
1332
  mSelector = new MediaRouteSelector.Builder()
1337
1333
  .addControlCategories(
@@ -1355,38 +1351,37 @@ public class FullscreenExoPlayerFragment extends Fragment {
1355
1351
  };
1356
1352
  CastButtonFactory.setUpMediaRouteButton(context, mediaRouteButton);
1357
1353
 
1358
- MediaMetadata movieMetadata;
1359
- if (artwork != "") {
1360
- movieMetadata = new MediaMetadata.Builder()
1361
- .setTitle(title)
1362
- .setSubtitle(smallTitle)
1363
- .setMediaType(MediaMetadata.MEDIA_TYPE_MOVIE)
1364
- .setArtworkUri(Uri.parse(artwork))
1365
- .build();
1354
+ if (hasArtwork()) {
1366
1355
  new setCastImage().execute();
1367
- } else {
1368
- movieMetadata = new MediaMetadata.Builder().setTitle(title).setSubtitle(smallTitle).build();
1369
1356
  }
1370
- mediaItem = new MediaItem.Builder()
1371
- .setUri(videoPath)
1372
- .setMimeType(MimeTypes.VIDEO_UNKNOWN)
1373
- .setMediaMetadata(movieMetadata)
1374
- .build();
1375
1357
 
1376
1358
  castPlayer.setSessionAvailabilityListener(
1377
1359
  new SessionAvailabilityListener() {
1378
1360
  @Override
1379
1361
  public void onCastSessionAvailable() {
1362
+ Uri castUri = getCastUri();
1363
+ if (!isNetworkUri(castUri)) {
1364
+ Toast.makeText(
1365
+ context,
1366
+ "Chromecast requires a network-reachable media URL",
1367
+ Toast.LENGTH_SHORT
1368
+ ).show();
1369
+ castContext.getSessionManager().endCurrentSession(false);
1370
+ return;
1371
+ }
1380
1372
  isCastSession = true;
1381
1373
  final Long videoPosition = player.getCurrentPosition();
1374
+ final boolean shouldPlay = player.getPlayWhenReady();
1382
1375
  if (pipEnabled) {
1383
1376
  pipBtn.setVisibility(View.GONE);
1384
1377
  }
1385
1378
  resizeBtn.setVisibility(View.GONE);
1386
1379
  player.setPlayWhenReady(false);
1387
1380
  cast_image.setVisibility(View.VISIBLE);
1388
- castPlayer.setMediaItem(mediaItem, videoPosition);
1389
1381
  styledPlayerView.setPlayer(castPlayer);
1382
+ castPlayer.setMediaItem(buildCastMediaItem(castUri), videoPosition);
1383
+ castPlayer.setPlayWhenReady(shouldPlay);
1384
+ castPlayer.prepare();
1390
1385
  styledPlayerView.setControllerShowTimeoutMs(0);
1391
1386
  styledPlayerView.setControllerHideOnTouch(false);
1392
1387
  //We perform a click because for some weird reason, the layout is black until the user clicks on it
@@ -1395,16 +1390,20 @@ public class FullscreenExoPlayerFragment extends Fragment {
1395
1390
 
1396
1391
  @Override
1397
1392
  public void onCastSessionUnavailable() {
1393
+ if (!isCastSession) return;
1398
1394
  isCastSession = false;
1399
1395
  final Long videoPosition = castPlayer.getCurrentPosition();
1396
+ final boolean shouldPlay = castPlayer.getPlayWhenReady();
1400
1397
  if (pipEnabled) {
1401
1398
  pipBtn.setVisibility(View.VISIBLE);
1402
1399
  }
1403
1400
  resizeBtn.setVisibility(View.VISIBLE);
1404
1401
  cast_image.setVisibility(View.GONE);
1402
+ castPlayer.stop();
1403
+ castPlayer.clearMediaItems();
1405
1404
  styledPlayerView.setPlayer(player);
1406
- player.setPlayWhenReady(true);
1407
1405
  player.seekTo(videoPosition);
1406
+ player.setPlayWhenReady(shouldPlay);
1408
1407
  styledPlayerView.setControllerShowTimeoutMs(3000);
1409
1408
  styledPlayerView.setControllerHideOnTouch(true);
1410
1409
  }
@@ -1418,7 +1417,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1418
1417
  Map<String, Object> info = new HashMap<String, Object>() {
1419
1418
  {
1420
1419
  put("fromPlayerId", playerId);
1421
- put("currentTime", String.valueOf(player.getCurrentPosition() / 1000));
1420
+ put("currentTime", String.valueOf(castPlayer.getCurrentPosition() / 1000));
1422
1421
  }
1423
1422
  };
1424
1423
  switch (state) {
@@ -1449,6 +1448,261 @@ public class FullscreenExoPlayerFragment extends Fragment {
1449
1448
 
1450
1449
  private final class EmptyCallback extends MediaRouter.Callback {}
1451
1450
 
1451
+ private Uri getCastUri() {
1452
+ return uri != null ? uri : Uri.parse(videoPath);
1453
+ }
1454
+
1455
+ private boolean isNetworkUri(Uri mediaUri) {
1456
+ String scheme = mediaUri.getScheme();
1457
+ return "http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme);
1458
+ }
1459
+
1460
+ private MediaItem buildCastMediaItem(Uri castUri) {
1461
+ MediaItem.Builder builder = buildMediaItem(castUri).buildUpon().setMediaMetadata(buildCastMediaMetadata());
1462
+ String mimeType = getMediaItemMimeType(castUri);
1463
+ if (mimeType != null) {
1464
+ builder.setMimeType(mimeType);
1465
+ }
1466
+ if (sturi != null && isNetworkUri(sturi)) {
1467
+ builder.setSubtitleConfigurations(Arrays.asList(buildSubtitleConfiguration(sturi, getMimeType(sturi))));
1468
+ }
1469
+ return builder.build();
1470
+ }
1471
+
1472
+ private MediaMetadata buildCastMediaMetadata() {
1473
+ MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder().setTitle(title).setSubtitle(smallTitle);
1474
+ if (hasArtwork()) {
1475
+ metadataBuilder.setMediaType(MediaMetadata.MEDIA_TYPE_MOVIE).setArtworkUri(Uri.parse(artwork));
1476
+ }
1477
+ return metadataBuilder.build();
1478
+ }
1479
+
1480
+ private boolean hasArtwork() {
1481
+ return artwork != null && !artwork.isEmpty();
1482
+ }
1483
+
1484
+ private MediaItem.SubtitleConfiguration buildSubtitleConfiguration(Uri subtitleUri, String mimeType) {
1485
+ String languageLabel = Locale.forLanguageTag(language).getDisplayLanguage();
1486
+ return new MediaItem.SubtitleConfiguration.Builder(subtitleUri)
1487
+ .setMimeType(mimeType)
1488
+ .setUri(subtitleUri)
1489
+ .setId(subTitle)
1490
+ .setLabel(languageLabel)
1491
+ .setRoleFlags(C.ROLE_FLAG_CAPTION)
1492
+ .setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
1493
+ .setLanguage(language)
1494
+ .build();
1495
+ }
1496
+
1497
+ private String getMediaItemMimeType(Uri mediaUri) {
1498
+ String mediaType = vType != null ? vType : getVideoType(mediaUri);
1499
+ switch (mediaType) {
1500
+ case "dash":
1501
+ case "mpd":
1502
+ return MimeTypes.APPLICATION_MPD;
1503
+ case "m3u8":
1504
+ return MimeTypes.APPLICATION_M3U8;
1505
+ case "ism":
1506
+ return MimeTypes.APPLICATION_SS;
1507
+ case "webm":
1508
+ return MimeTypes.VIDEO_WEBM;
1509
+ case "ogv":
1510
+ return "video/ogg";
1511
+ case "3gp":
1512
+ return "video/3gpp";
1513
+ case "flv":
1514
+ return "video/x-flv";
1515
+ case "mp4":
1516
+ return MimeTypes.VIDEO_MP4;
1517
+ case "ytube":
1518
+ case "":
1519
+ default:
1520
+ return null;
1521
+ }
1522
+ }
1523
+
1524
+ private final class SubtitleMediaItemConverter implements MediaItemConverter {
1525
+
1526
+ private static final String KEY_MEDIA_ITEM = "mediaItem";
1527
+ private static final String KEY_PLAYER_CONFIG = "exoPlayerConfig";
1528
+ private static final String KEY_MEDIA_ID = "mediaId";
1529
+ private static final String KEY_URI = "uri";
1530
+ private static final String KEY_TITLE = "title";
1531
+ private static final String KEY_MIME_TYPE = "mimeType";
1532
+ private static final String KEY_DRM_CONFIGURATION = "drmConfiguration";
1533
+ private static final String KEY_UUID = "uuid";
1534
+ private static final String KEY_LICENSE_URI = "licenseUri";
1535
+ private static final String KEY_REQUEST_HEADERS = "requestHeaders";
1536
+
1537
+ private final DefaultMediaItemConverter defaultConverter = new DefaultMediaItemConverter();
1538
+
1539
+ @Override
1540
+ public MediaQueueItem toMediaQueueItem(MediaItem mediaItem) {
1541
+ MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
1542
+ if (localConfiguration == null) {
1543
+ throw new IllegalArgumentException("The item must specify its local configuration");
1544
+ }
1545
+
1546
+ MediaInfo.Builder mediaInfoBuilder = new MediaInfo.Builder(getContentId(mediaItem, localConfiguration))
1547
+ .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
1548
+ .setContentUrl(localConfiguration.uri.toString())
1549
+ .setMetadata(buildCastMediaInfoMetadata(mediaItem))
1550
+ .setCustomData(buildCastCustomData(mediaItem));
1551
+
1552
+ if (localConfiguration.mimeType != null) {
1553
+ mediaInfoBuilder.setContentType(localConfiguration.mimeType);
1554
+ }
1555
+
1556
+ ArrayList<Long> activeTrackIds = new ArrayList<>();
1557
+ List<MediaTrack> mediaTracks = buildCastSubtitleTracks(localConfiguration.subtitleConfigurations, activeTrackIds);
1558
+ if (!mediaTracks.isEmpty()) {
1559
+ mediaInfoBuilder.setMediaTracks(mediaTracks);
1560
+ }
1561
+
1562
+ MediaQueueItem.Builder mediaQueueItemBuilder = new MediaQueueItem.Builder(mediaInfoBuilder.build());
1563
+ if (!activeTrackIds.isEmpty()) {
1564
+ mediaQueueItemBuilder.setActiveTrackIds(toLongArray(activeTrackIds));
1565
+ }
1566
+ return mediaQueueItemBuilder.build();
1567
+ }
1568
+
1569
+ @Override
1570
+ public MediaItem toMediaItem(MediaQueueItem mediaQueueItem) {
1571
+ return defaultConverter.toMediaItem(mediaQueueItem);
1572
+ }
1573
+
1574
+ private String getContentId(MediaItem mediaItem, MediaItem.LocalConfiguration localConfiguration) {
1575
+ return mediaItem.mediaId.equals(MediaItem.DEFAULT_MEDIA_ID) ? localConfiguration.uri.toString() : mediaItem.mediaId;
1576
+ }
1577
+
1578
+ private com.google.android.gms.cast.MediaMetadata buildCastMediaInfoMetadata(MediaItem mediaItem) {
1579
+ MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
1580
+ String mimeType = localConfiguration != null ? localConfiguration.mimeType : null;
1581
+ com.google.android.gms.cast.MediaMetadata metadata = new com.google.android.gms.cast.MediaMetadata(
1582
+ mimeType != null && MimeTypes.isAudio(mimeType)
1583
+ ? com.google.android.gms.cast.MediaMetadata.MEDIA_TYPE_MUSIC_TRACK
1584
+ : com.google.android.gms.cast.MediaMetadata.MEDIA_TYPE_MOVIE
1585
+ );
1586
+
1587
+ if (mediaItem.mediaMetadata.title != null) {
1588
+ metadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_TITLE, mediaItem.mediaMetadata.title.toString());
1589
+ }
1590
+ if (mediaItem.mediaMetadata.subtitle != null) {
1591
+ metadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_SUBTITLE, mediaItem.mediaMetadata.subtitle.toString());
1592
+ }
1593
+ if (mediaItem.mediaMetadata.artworkUri != null) {
1594
+ metadata.addImage(new WebImage(mediaItem.mediaMetadata.artworkUri));
1595
+ }
1596
+ return metadata;
1597
+ }
1598
+
1599
+ private List<MediaTrack> buildCastSubtitleTracks(
1600
+ List<MediaItem.SubtitleConfiguration> subtitleConfigurations,
1601
+ ArrayList<Long> activeTrackIds
1602
+ ) {
1603
+ ArrayList<MediaTrack> mediaTracks = new ArrayList<>();
1604
+ for (int i = 0; i < subtitleConfigurations.size(); i++) {
1605
+ MediaItem.SubtitleConfiguration subtitleConfiguration = subtitleConfigurations.get(i);
1606
+ if (subtitleConfiguration.uri == null) {
1607
+ continue;
1608
+ }
1609
+ long trackId = i + 1L;
1610
+ MediaTrack.Builder trackBuilder = new MediaTrack.Builder(trackId, MediaTrack.TYPE_TEXT)
1611
+ .setContentId(subtitleConfiguration.uri.toString())
1612
+ .setSubtype(MediaTrack.SUBTYPE_SUBTITLES);
1613
+ if (subtitleConfiguration.mimeType != null) {
1614
+ trackBuilder.setContentType(subtitleConfiguration.mimeType);
1615
+ }
1616
+ if (subtitleConfiguration.label != null) {
1617
+ trackBuilder.setName(subtitleConfiguration.label.toString());
1618
+ }
1619
+ if (subtitleConfiguration.language != null) {
1620
+ trackBuilder.setLanguage(subtitleConfiguration.language);
1621
+ }
1622
+ mediaTracks.add(trackBuilder.build());
1623
+ if ((subtitleConfiguration.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0) {
1624
+ activeTrackIds.add(trackId);
1625
+ }
1626
+ }
1627
+ return mediaTracks;
1628
+ }
1629
+
1630
+ private long[] toLongArray(List<Long> values) {
1631
+ long[] result = new long[values.size()];
1632
+ for (int i = 0; i < values.size(); i++) {
1633
+ result[i] = values.get(i);
1634
+ }
1635
+ return result;
1636
+ }
1637
+
1638
+ private JSONObject buildCastCustomData(MediaItem mediaItem) {
1639
+ try {
1640
+ JSONObject customData = new JSONObject();
1641
+ customData.put(KEY_MEDIA_ITEM, buildMediaItemJson(mediaItem));
1642
+ JSONObject playerConfig = buildPlayerConfigJson(mediaItem);
1643
+ if (playerConfig != null) {
1644
+ customData.put(KEY_PLAYER_CONFIG, playerConfig);
1645
+ }
1646
+ return customData;
1647
+ } catch (JSONException e) {
1648
+ throw new RuntimeException(e);
1649
+ }
1650
+ }
1651
+
1652
+ private JSONObject buildMediaItemJson(MediaItem mediaItem) throws JSONException {
1653
+ MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
1654
+ JSONObject json = new JSONObject();
1655
+ json.put(KEY_MEDIA_ID, mediaItem.mediaId);
1656
+ if (mediaItem.mediaMetadata.title != null) {
1657
+ json.put(KEY_TITLE, mediaItem.mediaMetadata.title.toString());
1658
+ }
1659
+ json.put(KEY_URI, localConfiguration.uri.toString());
1660
+ if (localConfiguration.mimeType != null) {
1661
+ json.put(KEY_MIME_TYPE, localConfiguration.mimeType);
1662
+ }
1663
+ if (localConfiguration.drmConfiguration != null) {
1664
+ json.put(KEY_DRM_CONFIGURATION, buildDrmConfigurationJson(localConfiguration.drmConfiguration));
1665
+ }
1666
+ return json;
1667
+ }
1668
+
1669
+ private JSONObject buildDrmConfigurationJson(MediaItem.DrmConfiguration drmConfiguration) throws JSONException {
1670
+ JSONObject json = new JSONObject();
1671
+ json.put(KEY_UUID, drmConfiguration.scheme.toString());
1672
+ json.put(KEY_LICENSE_URI, drmConfiguration.licenseUri.toString());
1673
+ json.put(KEY_REQUEST_HEADERS, new JSONObject(drmConfiguration.licenseRequestHeaders));
1674
+ return json;
1675
+ }
1676
+
1677
+ private JSONObject buildPlayerConfigJson(MediaItem mediaItem) throws JSONException {
1678
+ MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
1679
+ if (localConfiguration == null || localConfiguration.drmConfiguration == null) {
1680
+ return null;
1681
+ }
1682
+
1683
+ MediaItem.DrmConfiguration drmConfiguration = localConfiguration.drmConfiguration;
1684
+ String protectionSystem;
1685
+ if (C.WIDEVINE_UUID.equals(drmConfiguration.scheme)) {
1686
+ protectionSystem = "widevine";
1687
+ } else if (C.PLAYREADY_UUID.equals(drmConfiguration.scheme)) {
1688
+ protectionSystem = "playready";
1689
+ } else {
1690
+ return null;
1691
+ }
1692
+
1693
+ JSONObject json = new JSONObject();
1694
+ json.put("withCredentials", false);
1695
+ json.put("protectionSystem", protectionSystem);
1696
+ if (drmConfiguration.licenseUri != null) {
1697
+ json.put("licenseUrl", drmConfiguration.licenseUri.toString());
1698
+ }
1699
+ if (!drmConfiguration.licenseRequestHeaders.isEmpty()) {
1700
+ json.put("headers", new JSONObject(drmConfiguration.licenseRequestHeaders));
1701
+ }
1702
+ return json;
1703
+ }
1704
+ }
1705
+
1452
1706
  @Override
1453
1707
  public void onConfigurationChanged(Configuration newConfig) {
1454
1708
  super.onConfigurationChanged(newConfig);
@@ -38,7 +38,7 @@ import java.util.Map;
38
38
  )
39
39
  public class VideoPlayerPlugin extends Plugin {
40
40
 
41
- private final String pluginVersion = "8.1.6";
41
+ private final String pluginVersion = "8.1.8";
42
42
 
43
43
  // Permission alias constants
44
44
  private static final String PERMISSION_DENIED_ERROR = "Unable to access media videos, user denied permission request";
@@ -8,7 +8,7 @@ import AVKit
8
8
  */
9
9
  @objc(VideoPlayerPlugin)
10
10
  public class VideoPlayerPlugin: CAPPlugin, CAPBridgedPlugin {
11
- private let pluginVersion: String = "8.1.6"
11
+ private let pluginVersion: String = "8.1.8"
12
12
  public let identifier = "VideoPlayerPlugin"
13
13
  public let jsName = "VideoPlayer"
14
14
  public let pluginMethods: [CAPPluginMethod] = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-video-player",
3
- "version": "8.1.6",
3
+ "version": "8.1.8",
4
4
  "description": "Capacitor plugin to play video in native player",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",