In a Vue app I play background music, using the audio tag :
<audio id="music" autoplay loop>
<source
:src="musicfilename"
type="audio/mp3"
/>
</audio>
This works fine, but when the app is restarted during development, by Webpack 'hot reload', the music that was playing isn't stopped, so it keeps playing multiple music instances at the same time!
When I check with document.getElementsByTagName there is really only 1 instance of AUDIO, so I can't find a way to stop the previous audio instances from playing.
Any idea how to solve this problem?
You should track when your module is being hot replaced, and when it is just stop the audio player.
<audio id="music" ref="player" autoplay loop>
<source
:src="musicfilename"
type="audio/mp3"
/>
</audio>
export default {
...
mounted() {
if (module.hot) {
module.hot.dispose(this.hmrHandler);
}
},
destroyed() {
if (module.hot) {
module.hot.removeDisposeHandler(this.hmrHandler)
}
},
methods: {
hmrHandler() {
const { player } = this.$refs
player.pause()
// Lines below can also help
// player.currentTime = 0
// player.src = ''
},
},
...
}
Update:
Howler.unload() placed in the mounted hook solved the problem.
Webpack HMR API.
Look at dispose and removeDisposeHandler.
Related
What I have
I have made use of IntersectionObserver on my feed page. It behaves like TikTok. Scroll up or down to see the next video. On enter the video plays. On exit, it stops playing.
The Problem
It works on Android and Windows perfectly. On iOS, not so much. The videos are not autoplaying as expected. A bit strange though, is if I click the video (which calls play() on that video), and then scroll it out of view, the video does stop. When I scroll it back into view, it auto plays again. So I know that IntersectionObserver is being recognized, just not triggered initially.
The Code
==================================
The Feed Page, where the Observer is being instantiated:
data() {
return {
observer: null,
}
};
mounted() {
let config = { threshold: 0.1 };
if (process.client) {
if (/iPhone|iPad/i.test(navigator.userAgent)) {
config.root = null;
}
}
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(({ target, isIntersecting }) => {
if (isIntersecting) {
target.play();
} else {
target.pause();
target.currentTime = 0;
}
});
}, config);
beforeDestroy() {
this.observer.disconnect();
},
HTML
<div
v-for="(post, index) in posts"
:key="index"
>
<MobileFeedItem :post="post" :observer="observer" />
</div>
=================================
The MobileFeedItem component
props: ["post", "observer"],
mounted() {
this.$nextTick(() => {
if (this.observer !== null && this.checkMediaTypeIsVideo(this.post)) {
this.observer.observe(
document.getElementById(
`video_${this.getContentId(this.post)}_mobile`
)
);
}
});
HTML
<video
:id="`video_${getContentId(post)}_mobile`"
:data-poster="getThumbnail(post)"
preload="none"
disablePictureInPicture
crossorigin
loop
playsinline
v-lazy-load
class="w-full h-full my-4"
>
<source :data-src="getMedia(post)" type="video/mp4" />
</video>
My Thoughts...
The observer is being instantiated and recognized, just not triggered. So is there a way that I can force the browser to wake up and become aware of the observer without having to click on each of the video elements first?
I found the answer. It wasn't anything wrong with the IntersectionObserver, but because my video was not muted.
"By default, autoplay executes only if the video doesn’t contain an audio track, or if the video element includes the muted attribute. Video playback pauses if the element gains an audio track, becomes unmuted without user interaction, or if the video is no longer onscreen"
source - https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari
It also appears that we don't need intersection observer at all for Safari, as it does this for us. Huh.
I am using NativeScript with Angular. I want to add JW Player in app to play video for my app but I cannot figure it out. My code is like below:-
home.html
<GridLayout row="0" #jwVideoPlayer>
</GridLayout>
home.ts
import { Component, OnInit, ViewChild, ElementRef } from "#angular/core";
declare var jwplayer: any;
#Component({
selector: "home",
templateUrl: "./home.component.html",
})
export class HomeComponent implements OnInit {
#ViewChild('jwVideoPlayer', { static: false }) jwVideoPlayer: ElementRef;
ngOnInit() {
const playerJw = jwplayer('jwVideoPlayer').setup({
title: 'Player Test',
playlist: 'https://cdn.jwplayer.com/v2/media/8L4m9FJB',
width: 640,
height: 360,
aspectratio: '16:9',
mute: false,
autostart: true,
primary: 'html5',
});
}
}
I am getting below error for obvious reason as I could not figure out the way to include JW Player in NativeScript:-
ERROR ReferenceError: Can't find variable: jwplayer
In web project I generally used below line to include JW Player.
<script type="text/javascript">jwplayer.key="1D+blahblah/blahblah=="</script>
Do Nativescript support JW Player?
Can anyone please help me as how to include JW Player in NativeScript app?
You can use the nativescript-jwplayer-web plugin with the following command
npm i nativescript-jwplayer-web --save
I'm trying to add admob to my app with "nativescript-admob", here is the code i have for now :
<template>
<Page class="page">
<StackLayout class="hello-world">
<Label text="my home page"/>
</StackLayout>
</Page>
</template>
<script>
const admob = require("nativescript-admob");
export default {
mounted() {
admob.createBanner({
// if this 'view' property is not set, the banner is overlayed on the current top most view
// view: ..,
testing: true, // set to false to get real banners
size: admob.AD_SIZE.SMART_BANNER, // anything in admob.AD_SIZE, like admob.AD_SIZE.SMART_BANNER
androidBannerId: "ca-app-pub-AAAAAAAAAAA/AAAAAAAAA", // add your own
margins: {
// if both are set, top wins
//top: 10
bottom: 50
},
}).then(
function() {
console.log("admob createBanner done");
},
function(error) {
console.log("admob createBanner error: " + error);
}
)
},
}
</script>
i try to launch the admob on "mounted" but i cant make it work, does anyone integrated admob this way with nativescript-vue ? in my case i don't even see the log "admob createBanner done" log so maybe i don't use this plugin well.
the admob.createBanner() function has to be surrounded by a setTimeout() to launch after, it seems it has to be launch when a page is fully loaded. thx for the help of the slack nativescript-vue channel contributors !
My requirement is when the page loads the video should be start playing from the local storage and but it doesnt play at all.
Initially the state paused:true , and when the video loads i tried to change the state to false , but the video doesnt play automatically.
<Video
onEnd={this.handleEnd}
onLoad={this.handleLoad}
onProgress={this.handleProgress}
autoplay={true}
paused={this.state.paused}
ref={ref=> {
this.player = ref;
}}
resizeMode="cover"
source={{uri:this.state.v_url}}
volume={this.state.muted==true?0.0:1.0}
muted={this.state.muted}
/>
handleLoad = (meta) => {
console.log('Its working',this.props)
this.setState({
duration:meta.duration,
paused:false,
})
Use #coffeebeanslabs/react-native-inviewport to detect whether your component is in your device viewport:
Install using: npm i #coffeebeanslabs/react-native-inviewport
then do the following in your code:
import InViewPort from "#coffeebeanslabs/react-native-inviewport";
checkVideoVisible(isVideoVisible) {
this.setState({videoVisible: isVideoVisible});
}
<InViewPort onChange={(isVideoVisible) => this.checkVideoVisible(isVideoVisible)}>
<Video
paused={!this.state.videoVisible}
/>
</InViewPort>
I need to show Sound icon on top of the video, when sound is OFF and hide it when sound is ON. For some reason the code below is not working.
if (video.prop('muted') === true) {
video.mouseenter( function() {sound.show()} ).mouseleave( function() {sound.hide()} );
}
else {
sound.hide();
}
<video id="video" controls muted preload="none" width="446" height="250"></video>
I figured it out. Now it works like that.
video.mouseenter( function() {
if (video.prop('muted') === true) {
sound.show()
}
else {
sound.hide()
}
});
video.mouseleave( function() {
sound.hide();
});
Considering your video element:
<video id="video" controls muted preload="none" width="446" height="250">
</video>
You can determine whether sound is on by testing the volume and muted media properties of the element:
var video = document.getElementById("video");
if (video.muted || video.volume === 0) {
// Sound is off
}