66966 Не переключается selectedQuality при вызове setSelectedVideoQuality

This commit is contained in:
Алексей Манаев
2025-09-29 08:06:59 +00:00
parent e7eb4fdefa
commit fa52dda95b
11 changed files with 152 additions and 125 deletions
+6 -3
View File
@@ -63,8 +63,8 @@
player.afterInitialize(() => {
console.log('afterInitialize')
// player.setControlbarVisibility(true)
player.attachSource('https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd', { autoplay: 'muted' })
// player.attachSource("https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8", {autoplay: "muted"})
// player.attachSource('https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd', { autoplay: 'muted' })
player.attachSource("https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8", {autoplay: "muted"})
// player.attachSource("https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8", {autoplay: true})
// player.attachSource("https://dash.akamaized.net/dash264/TestCases/10a/1/iis_forest_short_poem_multi_lang_480p_single_adapt_aaclc_sidx.mpd", {autoplay: true})
// player.attachSource("https://streaming-iptv.voka.tv/eyJvc19uYW1lIjoibWFjIG9zIiwidXNlcl91aWQiOiIzMDE4ZmM2Yi02YmY4LTQ4OGQtOGRhMi02YjZmNWFmMjFjNDQiLCJkYXRhY2VudGVyIjoiaW50IiwiZG9tYWluX25hbWUiOiJzdHJlYW1pbmctaXB0di52b2thLnR2IiwiZHJtIjoic3BidHZjYXMiLCJleHBpcmF0aW9uX2RhdGUiOiIyMDI1LTA5LTA3VDA0OjA1OjI2WiIsImlwX2FkZHJlc3MiOiI4OS4xMTAuMTIyLjE3NSIsInByb2plY3QiOiJ2b2thX3Byb2R1Y3Rpb24iLCJwcm90b2NvbCI6ImhscyIsInNlc3Npb25faWQiOiIxNjU4Nzk0Zi1lNDRhLTRjMzctYmMzZi05YTFiMDc5YTk5YzAiLCJzdHJlYW1fbmFtZSI6IlBUWmNQaHJwTTN6Y0MzQ3RtRlppVEdkYkxuSGpINlBkUiIsInN0cmVhbV9wYXRoIjoiL3ZvZF92NS92ZWxjb20ifQ%3D%3D/MCwCFGxEXtZqOuKJDrL1lQtYVbbtDK4aAhQyj6sfG6I1q3GZ0feSVzzPRSjzbw%3D%3D/vod_v5/velcom/PTZcPhrpM3zcC3CtmFZiTGdbLnHjH6PdR.m3u8?b_app_channel_id=07497ccf-fa3f-473e-a254-9cfdba769ddb&b_app_id=voka_production&b_device_platform=mac%20os&b_device_uid=1d866e05-b0e5-e943-f49c-295ac85c20d7&b_stream_sid=1658794f-e44a-4c37-bc3f-9a1b079a99c0&b_strmr_channel_id=PTZcPhrpM3zcC3CtmFZiTGdbLnHjH6PdR&join_chunks=8", {autoplay: true})
@@ -140,8 +140,11 @@
'volumechange',
'controlbarShow',
'controlbarHide',
'qualitiesParsed',
'qualityUISet',
'qualitySet',
'qualityChange',
'sourceAttached',
// 'sourceAttached',
'zoomButtonChange',
'trackChange',
'bufferLengthUpdate',
+32
View File
@@ -157,6 +157,38 @@ getSelectedVideoQuality(): number;
* @returns number - индекс качества или -1 если неизвестно
*/
getPlayingVideoQuality(): number;
/**
* События
*/
/**
* Выбор качества - сигнал для теча попытаться изменить качество
* @paylad { index: number }
* index -1 - AUTO; 0 ... n – порядковый номер качества (см getVideoQualityList())
*/
'qualitySet'
/**
* Установка контрола выбранного качеста (без команды на изменения для теча)
* @paylad { index: number }
* index -1 - AUTO; 0 ... n – порядковый номер качества (см getVideoQualityList())
*/
'qualityUISet'
/**
* Фактическое изменнеи выбранного качества
* @paylad { index: number }
* index -1 - AUTO; 0 ... n – порядковый номер качества (см getVideoQualityList())
*/
'qualityChange'
/**
* Сигнал о доступности списка качеств
* @paylad { }
*/
'qualitiesParsed'
```
### 5. Управление звуком
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
import videojs from "video.js"
import videojs from 'video.js'
import Player from 'video.js/dist/types/player'
import { Quality, QualityLabelVariant } from "@/public/models/ILoadOptions"
import { QualityType, QualityMapper } from "@/public/models/QualityMapper"
@@ -20,9 +20,11 @@ class QualityButton extends MenuButton {
private qualitiesParsed: Cancellable | null
private qualityChange: Cancellable | null
private qualitySet: Cancellable | null
private qualityUISet: Cancellable | null
constructor(player: Player, options: VideoJsPlayerOptions) {
constructor(player: Player, options) {
super(player, options)
this.qualities = []
@@ -58,23 +60,37 @@ class QualityButton extends MenuButton {
this.qualityChange = this.bus.subscribe(
VokaBusEvent.qualityChange,
event => {
const payload = event.payload
const label = payload.isAuto
? QualityMapper.getLabelByQualityType(QualityType.AUTO, QualityLabelVariant.COMMON)
: ( payload.label || QualityMapper.getLabelByQualityType(QualityMapper.getQualityTypeByResolution(payload.width, payload.height) || QualityType.AUTO, QualityLabelVariant.COMMON) )
this.updateLabel(label || "")
const index = event.payload.index
let label: string | null | undefined
if (index > -1) {
const quality = this.qualities.find((quality: any) => {
return quality.index === index
})
label = quality?.label
} else {
label = QualityMapper.getLabelByQualityType(QualityType.AUTO, QualityLabelVariant.COMMON)
}
this.updateLabel(label ?? event.payload.label ?? '')
}
)
this.qualitySet = this.bus.subscribe(
VokaBusEvent.qualitySet,
event => {
const index = event.payload.index
this.items.map((item: any) => {
item.selected(item.value === index)
})
}
)
this.qualityUISet = this.bus.subscribe(
VokaBusEvent.qualityUISet,
event => {
const payload = event.payload
const label = QualityMapper.getLabelByValue(payload.quality, QualityLabelVariant.COMMON)
this.updateLabel(label || "")
console.log("qualityUISet: " + event.payload.quality)
const index = event.payload.index
this.items.map((item: any) => {
item.selected(item.value === index)
})
}
)
}
@@ -102,6 +118,7 @@ class QualityButton extends MenuButton {
this.resetSelected()
// set auto
const event = {
index: -1,
quality: Quality.AUTO,
forced: false,
withUIUpdate: true
@@ -135,19 +152,17 @@ class QualityButton extends MenuButton {
}
setActiveQuality(quality: VokaCorePlayer.IQualityData): void {
const result = this.items.find((item: any) => {
return item.value === quality.index
})
if (result) {
this.updateLabel(quality.label || "")
result.selected(true)
const event = {
quality: quality.quality,
forced: false,
withUIUpdate: true
} as VokaBusEvent.IQualitySet
this.bus.publish(VokaBusEvent.qualitySet(event))
const index = quality.index
if (index < -1 && index >= this.items.length) {
return
}
const event = {
index: index,
quality: quality.quality,
forced: false,
withUIUpdate: true
} as VokaBusEvent.IQualitySet
this.bus.publish(VokaBusEvent.qualitySet(event))
}
dispose() {
@@ -157,6 +172,9 @@ class QualityButton extends MenuButton {
if (this.qualityChange != null) { this.qualityChange() }
this.qualityChange = null
if (this.qualitySet != null) { this.qualitySet() }
this.qualitySet = null
if (this.qualityUISet != null) { this.qualityUISet() }
this.qualityUISet = null
+3 -28
View File
@@ -278,13 +278,7 @@ export default class VokaDash {
const qualitySetEvent = this.bus.subscribe(
VokaBusEvent.qualitySet,
event => {
const newQuality = event.payload.quality
const forced = event.payload.forced || false
const bandwidth = this.getBandwidth()
const newQualityIndex = this.getLevelByQualityAndBandwidth(
newQuality,
bandwidth
)
const newQualityIndex = event.payload.index
if (newQualityIndex === null) {
VokaError.fire(
@@ -292,33 +286,14 @@ export default class VokaDash {
VokaInternalErrorComponent.Player,
{
url: null,
message: `Quality ${newQuality} not found`,
message: `Quality with index ${newQualityIndex} not found`,
code: null,
}
)
return
}
console.debug("media player", this.mediaPlayer)
// Если текущий индекс качества соответствует проставляемому или авто
if (
newQualityIndex === DASH_LEVEL_AUTO ||
(
this.mediaPlayer &&
newQualityIndex != null &&
this.mediaPlayer.getCurrentRepresentationForType('video').absoluteIndex === newQualityIndex
)
) {
this.bus.publish(
VokaBusEvent.qualityUISet({
index: newQualityIndex,
quality: newQuality,
})
)
}
this.switchLevel(newQualityIndex, forced)
this.switchLevel(newQualityIndex, event.payload.forced || undefined)
},
)
+13 -21
View File
@@ -1,11 +1,10 @@
import type { EventBus } from 'ts-bus'
import videojs from 'video.js'
import VokaBusEvent from '@/internal/events/VokaBusEvent'
import type VokaCorePlayer from '@/internal/player/VokaCorePlayer'
import { Quality } from '@/public/models/ILoadOptions'
import type { EventBus } from 'ts-bus'
import videojs from 'video.js'
const log = videojs.log.createLogger('[VideoQualityObserver]')
const log = videojs.log.createLogger('[VideoQualityObserver]') as typeof videojs.log
namespace VideoQualityObserver {
export interface IQuality {
@@ -54,6 +53,10 @@ namespace VideoQualityObserver {
bus.subscribe(VokaBusEvent.qualityUISet, (event) => {
this.selectedIndex = event.payload.index
})
bus.subscribe(VokaBusEvent.qualitySet, (event) => {
this.selectedIndex = event.payload.index
})
}
// MARK: - IObserver
@@ -79,24 +82,13 @@ namespace VideoQualityObserver {
setSelectedVideoQuality(index: number) {
const quality = this.qualities.find((quality) => quality.index == index)
let event: VokaBusEvent.IQualitySet
if (quality == undefined) {
event = {
index: -1,
quality: Quality.AUTO,
forced: true,
const selectedIndex = quality?.index ?? -1
this.bus.publish(VokaBusEvent.qualitySet({
index: selectedIndex,
quality: selectedIndex < 0 ? Quality.AUTO : quality?.quality,
forced: false,
withUIUpdate: true
} as VokaBusEvent.IQualitySet
} else {
event = {
index: quality.index,
quality: quality.quality,
forced: true,
withUIUpdate: true
} as VokaBusEvent.IQualitySet
}
this.bus.publish(VokaBusEvent.qualitySet(event))
} as VokaBusEvent.IQualitySet))
}
}
}
+6 -6
View File
@@ -39,7 +39,7 @@ import '@/plugins/VokaLogPlugin'
import '@/plugins/VokaMagicRemotePlugin'
import '@/plugins/VokaMetricsPlugin'
const log = videojs.log.createLogger('[VokaCorePlayer]')
const log = videojs.log.createLogger('[VokaCorePlayer]') as typeof videojs.log
namespace VokaCorePlayer {
type VideoJsPlayerOptions = Parameters<typeof videojs>[1]
@@ -700,18 +700,18 @@ namespace VokaCorePlayer {
this.updateBufferingMode(false)
}
})
player.on('canplay', this.updateTimeshift)
player.on('canplay', () => this.updateTimeshift(false))
player.one('playing', () => {
player.childNameIndex_['PosterImage'].hide()
})
player.on('canplay', this.changeZoomButtonVisible)
player.on(VokaEvent.MasterDashManifestParsed, this.changeZoomButtonVisible)
window.addEventListener('resize', this.changeZoomButtonVisible, true)
player.on('canplay', () => this.changeZoomButtonVisible())
player.on(VokaEvent.MasterDashManifestParsed, () => this.changeZoomButtonVisible())
window.addEventListener('resize', this.changeZoomButtonVisible(), true)
}
private detachListeners(player: Player) {
window.removeEventListener('resize', this.changeZoomButtonVisible, true)
window.removeEventListener('resize', this.changeZoomButtonVisible(), true)
player.off(VokaEvent.MasterDashManifestParsed)
player.off(['canplay', 'playing', 'ended', 'play', 'waiting', 'loadstart'])
}
@@ -313,15 +313,6 @@ export default class HlsProcessor {
newQualityIndex = HLS_LEVEL_AUTO
}
if (newQualityIndex === HLS_LEVEL_AUTO || newQualityIndex == this.hls.currentLevel) {
this.bus.publish(
VokaBusEvent.qualityUISet({
index: newQualityIndex,
quality: newQuality,
})
)
}
this.switchLevel(newQualityIndex)
}
)
@@ -731,4 +722,4 @@ export default class HlsProcessor {
return prev
})
}
}
}
@@ -1,23 +1,27 @@
import { IContextUpdated } from '@/public/@types'
import Hls from 'hls.js'
import { Level, MediaPlaylist } from 'hls.js/lib/types/level'
import AudioTrack from 'video.js/dist/types/tracks/audio-track'
import type { Level, MediaPlaylist } from 'hls.js/lib/types/level'
import type { EventBus } from 'ts-bus'
import videojs from 'video.js'
import type AudioTrack from 'video.js/dist/types/tracks/audio-track'
import VokaEvent from '@/constants/VokaEvent'
import VokaBusEvent from '@/internal/events/VokaBusEvent'
import HlsLoadContext from '@/internal/player/native/hls/processors/HlsLoadContext'
import HlsProcessor from '@/internal/player/native/hls/processors/HlsProcessor'
import VokaHlsSourceHandler from '@/internal/player/native/hls/sourcehandler/VokaHlsSourceHandler'
import { on, trigger } from '@/internal/utils/events'
import * as Fn from '@/internal/utils/fn'
import { wait } from '@/monads/Monoids'
import VokaHlsSourceHandler from '@/internal/player/native/hls/sourcehandler/VokaHlsSourceHandler'
import HlsLoadContext from '@/internal/player/native/hls/processors/HlsLoadContext'
import PlatformCapabilities from '@/internal/utils/PlatformCapabilities'
import VokaEvent from '@/constants/VokaEvent'
import { IVokaSource, VokaSourceHandler } from '../../VokaSourceHandler'
import VokaBusEvent from '@/internal/events/VokaBusEvent'
import { QualityLabelVariant } from '@/public/models/ILoadOptions'
import VokaTech from '../../VokaTech'
import { wait } from '@/monads/Monoids'
import { Environment } from '@/public/models/Environment'
import { QualityLabelVariant } from '@/public/models/ILoadOptions'
import { Quality } from '@/public/models/ILoadOptions'
import { QualityMapper } from '@/public/models/QualityMapper'
import { EventBus } from 'ts-bus'
import type { IVokaSource} from '../../VokaSourceHandler'
import { VokaSourceHandler } from '../../VokaSourceHandler'
import VokaTech from '../../VokaTech'
const Dom = videojs.dom
const browser = videojs.browser
@@ -86,37 +90,37 @@ class VokaHlsTech extends VokaTech.Tech {
}
private getAudioTrackItems(audioTracks: MediaPlaylist[]) {
const tracks: AudioTrack[] = [];
const tracks: AudioTrack[] = []
audioTracks.forEach((value) => {
if (typeof tracks[value.id] === 'undefined') {
const track = new videojs.AudioTrack({
id: value.id,
kind: value.default ? 'main' : 'alternative',
language: value.lang,
enabled: value.default,
label: value.name || value.lang
});
})
tracks[value.id] = track;
tracks[value.id] = track
}
})
return tracks;
return tracks
}
private emitQualityValues(qualities: IQualityLevel): void {
private emitQualityValues(qualities: IQualityLevel[]): void {
if (qualities.length === 0) {
this.bus.publish(
VokaBusEvent.contextUpdated({
isAutoQuality: true,
quality: Quality.AUTO
})
} as IContextUpdated)
)
}
if (qualities.length > 0) {
this.bus.publish(
VokaBusEvent.qualitiesParsed({
selected: -1,
qualities
})
)
@@ -130,10 +134,11 @@ class VokaHlsTech extends VokaTech.Tech {
VokaBusEvent.contextUpdated({
isAutoQuality: false,
quality: qualities[0].quality
})
} as IContextUpdated)
)
this.bus.publish(
VokaBusEvent.qualityUISet({
index: 0,
quality: qualities[0].quality
})
)
@@ -195,12 +200,12 @@ class VokaHlsTech extends VokaTech.Tech {
src: tr.url,
default: tr.default,
enabled: true,
};
}
})
this.emitMediaTracks('subtitle', subtitle)
this.setCurrentSubtitles(-1)
const audioTracks = this.getAudioTrackItems(data.audioTracks);
const audioTracks = this.getAudioTrackItems(data.audioTracks)
this.emitMediaTracks('audio', audioTracks)
this.trigger(VokaEvent.PlayerMetadataLoaded)
@@ -1,4 +1,5 @@
import VokaBusEvent from '@/internal/events/VokaBusEvent'
import { IContextUpdated } from '@/public/@types'
import { QualityMapper } from '@/public/models/QualityMapper'
import { QualityLabelVariant } from '@/public/models/ILoadOptions'
import Player from 'video.js/dist/types/player'
@@ -46,7 +47,7 @@ export default class Mp4Processor {
VokaBusEvent.contextUpdated({
isAutoQuality: false,
quality: qualities[0].quality,
})
} as IContextUpdated)
)
this.bus.publish(
@@ -57,4 +58,4 @@ export default class Mp4Processor {
)
})
}
}
}
+18 -8
View File
@@ -1,11 +1,13 @@
import { data } from "autoprefixer";
import type { EventBus } from 'ts-bus'
import videojs from 'video.js'
import Player from 'video.js/dist/types/player'
import EventUtils from '../internal/utils/EventUtils'
import ZoomModeObserver from '@/internal/observers/ZoomModeObserver'
import type Player from 'video.js/dist/types/player'
import VokaBusEvent from '@/internal/events/VokaBusEvent'
import SelectionObserver from '@/internal/observers/SelectionObserver'
import { EventBus } from 'ts-bus'
import ZoomModeObserver from '@/internal/observers/ZoomModeObserver'
import EventUtils from '../internal/utils/EventUtils'
namespace VokaEventsMapperPlugin {
@@ -78,9 +80,17 @@ namespace VokaEventsMapperPlugin {
VokaBusEvent.qualityChange,
event => { this.fireEvent('qualityChange', { index: event.payload.index } as EventUtils.IEventData) },
)
options.bus.subscribe(
VokaBusEvent.qualitySet,
event => { this.fireEvent('qualitySet', { index: event.payload.index } as EventUtils.IEventData) },
)
options.bus.subscribe(
VokaBusEvent.qualityUISet,
event => { this.fireEvent('qualityChange', { index: event.payload.index } as EventUtils.IEventData) },
event => { this.fireEvent('qualityUISet', { index: event.payload.index } as EventUtils.IEventData) },
)
options.bus.subscribe(
VokaBusEvent.qualitiesParsed,
event => { this.fireEvent('qualitiesParsed', {} as EventUtils.IEventData) },
)
// new stream source was set
@@ -95,7 +105,7 @@ namespace VokaEventsMapperPlugin {
},
)
// current audio/subtitles track changed
// current video/audio/subtitles track changed
options.bus.subscribe(
VokaBusEvent.qualityChange,
event => { this.fireEvent('trackChange', { mediaType: 'video' } as EventUtils.IEventData) },
@@ -235,4 +245,4 @@ namespace VokaEventsMapperPlugin {
}
videojs.registerPlugin(VokaEventsMapperPlugin.name, VokaEventsMapperPlugin.Plugin)
export default VokaEventsMapperPlugin
export default VokaEventsMapperPlugin