public void updateRepresentation(long newPeriodDurationUs, Representation newRepresentation) throws BehindLiveWindowException{ DashSegmentIndex oldIndex = representation.getIndex(); DashSegmentIndex newIndex = newRepresentation.getIndex(); periodDurationUs = newPeriodDurationUs; representation = newRepresentation; if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. return; } segmentIndex = newIndex; if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. return; } int oldIndexLastSegmentNum = oldIndex.getLastSegmentNum(periodDurationUs); long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum) + oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs); int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum(); long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum); if (oldIndexEndTimeUs == newIndexStartTimeUs) { // The new index continues where the old one ended, with no overlap. segmentNumShift += oldIndex.getLastSegmentNum(periodDurationUs) + 1 - newIndexFirstSegmentNum; } else if (oldIndexEndTimeUs < newIndexStartTimeUs) { // There's a gap between the old index and the new one which means we've slipped behind the // live window and can't proceed. throw new BehindLiveWindowException(); } else { // The new index overlaps with the old one. segmentNumShift += oldIndex.getSegmentNum(newIndexStartTimeUs, periodDurationUs) - newIndexFirstSegmentNum; } }
public void updatePeriod(MediaPresentationDescription manifest, int manifestIndex, ExposedTrack selectedTrack) throws BehindLiveWindowException { Period period = manifest.getPeriod(manifestIndex); long periodDurationUs = getPeriodDurationUs(manifest, manifestIndex); List<Representation> representations = period.adaptationSets .get(selectedTrack.adaptationSetIndex).representations; for (int j = 0; j < representationIndices.length; j++) { Representation representation = representations.get(representationIndices[j]); representationHolders.get(representation.format.id).updateRepresentation(periodDurationUs, representation); } updateRepresentationIndependentProperties(periodDurationUs, representations.get(representationIndices[0])); }
private void processManifest(MediaPresentationDescription manifest) { // Remove old periods. Period firstPeriod = manifest.getPeriod(0); while (periodHolders.size() > 0 && periodHolders.valueAt(0).startTimeUs < firstPeriod.startMs * 1000) { PeriodHolder periodHolder = periodHolders.valueAt(0); // TODO: Use periodHolders.removeAt(0) if the minimum API level is ever increased to 11. periodHolders.remove(periodHolder.localIndex); } // After discarding old periods, we should never have more periods than listed in the new // manifest. That would mean that a previously announced period is no longer advertised. If // this condition occurs, assume that we are hitting a manifest server that is out of sync and // behind, discard this manifest, and try again later. if (periodHolders.size() > manifest.getPeriodCount()) { return; } // Update existing periods. Only the first and last periods can change. try { int periodHolderCount = periodHolders.size(); if (periodHolderCount > 0) { periodHolders.valueAt(0).updatePeriod(manifest, 0, enabledTrack); if (periodHolderCount > 1) { int lastIndex = periodHolderCount - 1; periodHolders.valueAt(lastIndex).updatePeriod(manifest, lastIndex, enabledTrack); } } } catch (BehindLiveWindowException e) { fatalError = e; return; } // Add new periods. for (int i = periodHolders.size(); i < manifest.getPeriodCount(); i++) { PeriodHolder holder = new PeriodHolder(nextPeriodHolderIndex, manifest, i, enabledTrack); periodHolders.put(nextPeriodHolderIndex, holder); nextPeriodHolderIndex++; } // Update the available range. TimeRange newAvailableRange = getAvailableRange(getNowUnixTimeUs()); if (availableRange == null || !availableRange.equals(newAvailableRange)) { availableRange = newAvailableRange; notifyAvailableRangeChanged(availableRange); } currentManifest = manifest; }
@Override public void onError(Exception e) { String errMsg = "Player Error"; LOGE(TAG, errMsg, e); String errorString = ""; if (e instanceof UnsupportedDrmException) { // Special case DRM failures. UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e; errorString = (Util.SDK_INT < 18) ? "error_drm_not_supported" : unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME ? "error_drm_unsupported_scheme" : "error_drm_unknown"; } else if (e instanceof ExoPlaybackException && e.getCause() instanceof FileNotFoundException) { errorString = "DRM License Unavailable"; // probably license issue } else if (e instanceof ExoPlaybackException && e.getCause() instanceof BehindLiveWindowException) { LOGE(TAG, "Recovering BehindLiveWindowException"); // happens if network is bad and no more chunk in hte buffer mExoPlayer.prepare(); return; } else if (e instanceof ExoPlaybackException && e.getCause() instanceof android.media.MediaCodec.CryptoException) { errorString = "DRM Error. Trying to recover"; // probably license issue mExoPlayer.prepare(); return; } else if (e instanceof ExoPlaybackException && e.getCause() instanceof MediaCodecTrackRenderer.DecoderInitializationException) { // Special case for decoder initialization failures. MediaCodecTrackRenderer.DecoderInitializationException decoderInitializationException = (MediaCodecTrackRenderer.DecoderInitializationException) e.getCause(); if (decoderInitializationException.decoderName == null) { if (decoderInitializationException.getCause() instanceof MediaCodecUtil.DecoderQueryException) { errorString = "error_querying_decoders "; } else if (decoderInitializationException.secureDecoderRequired) { errorString = "error_no_secure_decoder " + decoderInitializationException.mimeType; } else { errorString = "error_no_decoder " + decoderInitializationException.mimeType; } } else { errorString = "error_instantiating_decoder " + decoderInitializationException.decoderName; } } else if (e.getCause() instanceof com.google.android.exoplayer.upstream.HttpDataSource.HttpDataSourceException) { mExoPlayer.prepare(); errorString = "HttpDataSourceException . Trying to recover"; LOGE(TAG, errorString); return; } else if (e.getCause() instanceof java.net.UnknownHostException) { mExoPlayer.prepare(); errorString = "UnknownHostException . Trying to recover"; LOGE(TAG, errorString); return; } else if (e.getCause() instanceof java.net.ConnectException) { mExoPlayer.prepare(); errorString = "ConnectException . Trying to recover"; LOGE(TAG, errorString); return; } else if (e.getCause() instanceof java.lang.IllegalStateException) { mExoPlayer.prepare(); errorString = "IllegalStateException . Trying to recover"; LOGE(TAG, errorString); return; } if (!"".equals(errorString)) { LOGE(TAG, errorString); errorString += "-"; } mPlayerListener.eventWithValue(KExoPlayer.this, KPlayerListener.ErrorKey, TAG + "-" + errMsg + "-" + errorString + e.getMessage()); }