- Device & Environment
-
Device: Vega OS
-
App type: WebView app AmazonWebViewComponent
-
Player: Shaka Player v5.0.8 running inside WebView
-
Content: DASH/MP4 VOD , HD variant ~7Mbps, 2s segments, Widevine L1 DRM protected
Problem
During HD VOD playback of Widevine L1 DRM protected content,
SourceBuffer.appendBuffer()throws
QuotaExceededError(Shaka error code 3014) at approximately 5- 10mins into the content. This causes Shaka to disable the HD stream, switch to the lowest quality variant, and seek back to position 0 — causing a visible interruption to the user.
This does not happen on Any other platform we support.
drm: {
servers: { 'com.widevine.alpha': licenseUrl },
defaultVideoRobustnessForWidevine: 'HW_SECURE_ALL',
defaultAudioRobustnessForWidevine: 'SW_SECURE_CRYPTO',
advanced: {
'com.widevine.alpha': {
videoRobustness: ['HW_SECURE_ALL'],
audioRobustness: ['SW_SECURE_CRYPTO']
}
}
}
Because the content is Widevine L1the video decoder uses a secure hardware buffer. We believe this secure hardware buffer has a separate, smaller memory allocation than the regular MSE buffer — and this is what is being exhausted, not the JS-visible storage quota.
navigator.storage.estimate() → quota: 2637MBThe JS-visible storage quota is not the constraint. Something below the JS layer is limiting MSE buffer size.
At the point of failure:
video=4458000 Evicting at 0 QUOTA_EXCEEDED: buffered= 1138.0 - 1140.0, range= 2.0sOnly 2 seconds of HD video is in the buffer when quota is exceeded. This is extremely low compared to desktop Chrome where 30–60s can be buffered without issue.
What We Have Tried
Approach Result bufferingGoal: 4(Shaka default)Error 3014 occurs at approximately 5- 10 mins into playback. bufferingGoal: 2,bufferBehind: 2Error 3014 still occurs, but slightly later in playback. bufferingGoal: 1,bufferBehind: 1Reduces the frequency of 3014, but ABR becomes permanently stuck on the lowest-quality variant. unload() + load(url, currentTime)on 3014Triggers a new EME session; DRM token has already expired, resulting in HTTP 403 from the license server. currentTime + 0.1seek/nudge on 3014No effect. Shaka has already internally disabled the stream and seeks back to position 0. The JS-visible quota (
navigator.storage.estimate()= 2637MB) is the filesystem quota, not the MSE decoder buffer quota. For Widevine L1
content, the video data is written into a secure hardware memory region managed by the TEE and the secure video path. This secure buffer has a fixed allocation that is separate from and much smaller than the general Chromium MSE buffer.
Questions
-
What is the secure video buffer size allocated for Widevine L1 HW_SECURE_ALL content in the Vega WebView? Is this configurable per app?
-
Is SourceBuffer.remove() truly synchronous at the secure hardware buffer level on Vega, or is there a delay before TEE/secure memory is freed?
-
Is there a Chromium flag, WebView configuration, or platform API to increase the secure MSE buffer allocation for a specific WebView app?
-
Is there a way to query the actual available secure buffer memory at runtime from JS? (
navigator.storage.estimate()does not reflect this)
-
Does the Vega WebView support
MediaSource.isTypeSupported()hints or any mechanism to signal preferred buffer sizes to the secure video path?
Thanks,
Hari
-
-
Hi @Hari_Krishnan ,
Thank you for the thorough report.
Answering your questions:
1. Secure video buffer size for Widevine L1 HW_SECURE_ALL: This is determined by the SoC’s Trusted Execution Environment (TEE) and is not configurable per app. The exact allocation is platform-specific and not exposed via any public API. I am checking internally to get the specific size for the Fire TV 4K Select.
2. Is SourceBuffer.remove() synchronous at the secure buffer level? There may be a delay before secure memory is actually freed. The TEE handles buffer lifecycle independently of the Chromium MSE layer. This could explain why aggressive eviction strategies (bufferBehind: 1) don’t fully prevent the error - the memory may not be reclaimed in time for the next appendBuffer() call.
3. Chromium flag or API to increase secure MSE buffer allocation? There is no developer-facing Chromium flag or WebView configuration to increase the secure buffer size. This is a hardware-level constraint.
4. Runtime query for available secure buffer memory? No - navigator.storage.estimate() only reflects the filesystem quota. There is currently no JS API to query the secure video buffer remaining capacity on Vega OS.
5. MediaSource.isTypeSupported() hints for buffer sizes? No - isTypeSupported() only indicates codec/container support, not buffer capacity.
Recommended workaround while we investigate:
Based on the Vega Shaka Player Dynamic Buffering guide, configure Shaka to work within the secure buffer constraint:
player.configure({
streaming: {
bufferingGoal: 2, // Only buffer 2s ahead
bufferBehind: 0, // Don't retain any played content
rebufferingGoal: 0.5,
safeSeekOffset: 1,
evictionGoal: 1, // Aggressively evict
},
abr: {
enabled: true,
// Do NOT disable ABR — let it adapt to buffer pressure
}
});
Additionally, handle the 3014 error gracefully instead of letting Shaka’s default behavior seek to position 0:
player.addEventListener('error', (event) => {
if (event.detail.code === 3014) {
// QuotaExceededError — evict manually and retry
const video = document.querySelector('video');
const buffered = video.buffered;
if (buffered.length > 0) {
const sourceBuffer = mediaSource.sourceBuffers[0];
// Remove everything behind current position
sourceBuffer.remove(buffered.start(0), video.currentTime - 0.5);
}
}
});
Next Steps:
I’m checking internally to:
1. Confirm the exact secure buffer size on the Fire TV 4K Select hardware
2. Determine if there’s a planned fix or platform-level mitigation
3. Evaluate whether a future OS update can expose secure buffer capacity to the MSE layer
I’ll update this case once we have answers from the platform team.
Relevant documentation:
Warm regards,
Ivy
Thank you @Ivy for the detailed response. We have implemented and tested all the recommended configurations. Here is what we observed:
Configuration :
streaming: {
bufferingGoal: 4,
bufferBehind: 0,
rebufferingGoal: 0.5,
safeSeekOffset: 1,
evictionGoal: 1
}
1:
bufferingGoal: 2 starves ABR
With bufferingGoal: 2 , ABR had insufficient headroom to measure bandwidth and was permanently stuck at the lowest bitrate (480x272/648k) for the entire session. We raised it to 4 which gave ABR enough runway to select appropriate variants. We would appreciate guidance on the minimum bufferingGoal that works within the secure buffer constraint while still allowing ABR to function correctly.
2:
sourceBuffer.remove() from outside Shaka is not viable
Regarding the recommended 3014 handler — Shaka owns the MediaSource internally and does not expose it publicly. We attempted to intercept window.MediaSource.prototype.addSourceBuffer to capture Shaka’s internal SourceBuffer references. However when 3014 fires, Shaka has already detached the SourceBuffer from the MediaSource before our error handler runs — we get
InvalidStateError: This SourceBuffer has been removed from the parent media source
The captured references are stale by the time 3014 reaches us. sourceBuffer.remove() is definitively not callable from outside Shaka.
3:
bufferBehind: 0 does not prevent 3014
We confirmed that bufferBehind: 0 does not prevent 3014. When 3014 fired, the JS-visible buffer was already empty (buffered= 0.0 - 0.0) at currentTime= 2059s. There was nothing left to evict, yet appendBuffer() still threw QuotaExceededError. This directly confirms your statement that SourceBuffer.remove() has an async delay at the TEE level — the JS-visible buffer was empty but the secure memory had not yet been freed. No JS-level eviction strategy can prevent this.
When 3014 fired,
buffered= 0.0 - 0.0
— the JS-visible buffer was completely empty. This means the TEE secure buffer is holding memory that is invisible to Chromium’s MSE layer. No JS API can query it, no JS eviction can free it in time. This is a platform-level constraint that cannot be worked around from application JS.
Thanks,
Hari
Thanks @Hari_Krishnan , checking this.