I have an audioplayer application which uses audio_service and just_audio plugins for playback. Everything seems fine but there are 2 issues that I am facing.
The player position is out of sync, the duration becomes the position but when I pause the audio it reflects the right position. This behaviour can be seen on the notifications and on the AudioService.positionStream which is updating the seek bar on Flutter UI.
Audio stops playing on lock screen out of the blue.
My code:
_playbackSubscription = _player.playbackEventStream.listen((event) {
setState(_player, event);
});
void setState(AudioPlayer _player, event) {
if (queue == null || queue.isEmpty) return;
var controls = [
MediaControl.skipToPrevious,
_player.playing ? MediaControl.pause : MediaControl.play,
MediaControl.skipToNext,
MediaControl.stop
];
AudioServiceBackground.setMediaItem(
queue.elementAt(_player.currentIndex).copyWith(
duration: _player.duration,
));
AudioServiceBackground.setState(
playing: _player.playing,
bufferedPosition: _player.bufferedPosition,
speed: _player.speed,
shuffleMode: _player.shuffleModeEnabled
? AudioServiceShuffleMode.all
: AudioServiceShuffleMode.none,
repeatMode:
AudioServiceRepeatMode.values.elementAt(_player.loopMode.index),
position: _player.position,
processingState: {
ProcessingState.idle: AudioProcessingState.none,
ProcessingState.loading: AudioProcessingState.connecting,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingState.completed: AudioProcessingState.completed,
}[_player.processingState],
systemActions: [
MediaAction.seekBackward,
MediaAction.seekTo,
MediaAction.seekForward
],
controls: controls,
updateTime: event?.updateTime ?? DateTime.now());
}
Code Block Summary: Basically setting the AudioService state whenever the player state changes.
Related
I'm developing camera app right now.
I finished most of important features but the most important feature left.
I want my app auto exposure mode.
Here is my sample.
do {
try camera.lockForConfiguration()
camera.focusMode = .continuousAutoFocus
camera.exposureMode = .continuousAutoExposure
camera.unlockForConfiguration()
} catch {
return
}
I made this setting between lockForConfiguration and unlockForConfiguration.
This lead to autoexposure, however it is different from native camera app.
Also, shutter speed does not go below 1/40.
It is always 1/40 whenever it is in dark environment.(where native camera app adjust shutter speed to 1/2 or even 1)
I found the answer here (https://developer.apple.com/forums/thread/26227)
But I don't understand this answer and even how to do that...
session.beginConfiguration()
defer {
session.commitConfiguration()
}
device = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back)
guard let camera = device else {
set(error: .cameraUnavailable)
status = .failed
return
}
I set AVCapturedevice in this code. Also there is a session.
The answer says don't touch sessionpreset, so I did do anything by sessionPreset.
But how can I set the avcapturedevice by activeformat..?
This is very hard to understand.
Just to check if this is work, I added this codes just below above codes.
'''
var bestFormat: AVCaptureDevice.Format?
bestFormat = device!.formats[2]
print(self.device?.formats)
do {
try camera.lockForConfiguration()
camera.focusMode = .continuousAutoFocus
camera.exposureMode = .continuousAutoExposure
camera.activeFormat = bestFormat!
// camera.setExposureModeCustom(duration: CMTime(value: 1, timescale: 500), iso: 2000)
camera.unlockForConfiguration()
} catch {
return
}
'''
I believe this does not work because camera-resolution doesn't change.
even if device!.formats[2] is low resolution for me (I checked it)
I am using react-native-track-player package to play music files in my React Native mobile application.
There due to some issue, I need to stop the track-player once the queue of audio tracks reaches the end. For that, I use the event PlaybackQueueEnded to invoke the following code snippet. (I have used it in the useTrackPlayerEvents hook along with the PlayerTrackChanged event which when fired, sets the title, author, and background of the current audio file being played).
useTrackPlayerEvents(
// To set the title, author, and background of the current audio file being played
[Event.PlaybackTrackChanged, Event.PlaybackQueueEnded],
async event => {
if (
event.type === Event.PlaybackTrackChanged &&
event.nextTrack !== null
) {
const track = await TrackPlayer.getTrack(event.nextTrack);
const title = track?.title;
const artist = track?.artist;
const artwork: SetStateAction<any> = track?.artwork;
setTrackTitle(title);
setTrackArtist(artist);
setTrackArtwork(artwork);
}
// To stop the player once it reaches the end of the queue
if (
event.type === Event.PlaybackQueueEnded &&
event.position === progress.duration
) {
TrackPlayer.stop();
}
},
);
But the above code doesn't work as I expected. Seems the event PlaybackQueueEnded is not fired when playing the last track of the queue. Can somebody please help me to solve this issue?
Thank you.
PS: I am taking the current time and duration of the audio file being played by using the useProgress hook and have assigned its value to the progress variable. By that, I'm taking progress.position and progress.duration.
PlaybackQueueEnded will be fired when the song is finished and you dont need to check if event.position === progress.duration
I made custom feature to stop auto play when user hover on swiper. It is working but there is a problem. It won't stop immediately, instead of it has delay time = swiper's speed. How to stop it immediately. Please help me.
swiper.hover( function() {
swiper.autoplay.stop();
}, function() {
swiper.autoplay.start();
} );
How can I implement Hammer.js to catch only swipeLeft and swipeRight events on devices without mouse?
In the source code of hammer.js I found that a var INPUT_TYPE_MOUSE = 'mouse'; exists. In the documentation I did not find how to disable it with the options.
Have I to disable all recognizers in a preset if I only want to use the swipe recognizer?
preset: [
// RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
[RotateRecognizer, { enable: false }],
[PinchRecognizer, { enable: false }, ['rotate']],
[SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }],
[PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']],
[TapRecognizer],
[TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']],
[PressRecognizer]
],
How can I do this by the options?
To use only Swipe recognizer you can do this:
var mc = new Hammer.Manager(element, managerOptions);
mc.add(new Hammer.Swipe(recognizerOptions));
mc.on('swipeleft', leftSwipeHandler);
mc.on('swiperight', rightSwipeHandler);
It's described in More Control Section in documentation.
This will recognize swipe not only in touch devices but also in those that use mouse. I don't know how to disable firing this event in mouse devices. But I think that after event's been fired you can check in handler function what kind of pointer caused the event. Use event's pointerType property for that purpose:
var leftSwipeHandler = function (event) {
if (event.pointerType === 'mouse')
return;
// some more code
}
If you use jquery plugin then this property is in gesture object: event.gesture.pointerType.
Double clicking fast on a button in Sencha Touch 2 when having a navigation view will on some Android device push the new view twice on the view stack, how to solve it? Doesnt happen on iPhone
If you're having problems with the single click, then wrap the event function in a delayed task... for instance:
tap: function(button, e, eOpts) {
if(this.delayedTask == null){
this.delayedTask = Ext.create('Ext.util.DelayedTask', function() {
this.myFunctionToCall();
this.delayedTask = null;
}, this);
this.delayedTask.delay(500);
}
}
So in the example above, if another tap is registered and this.delayedTask has yet to be null, then it will not create the new delayed task which ultimately calls whatever function you need after 500 miliseconds... hope this makes sense, it's also a way to create double tap events on buttons...
This issue is a bit old but I was facing the same issue in the app I'm working on in my company. This is especially frustrating when buttons are bound to an Ajax call.
I took back Jeff Wooden's solution to override every button in my app :
Ext.define('MyApp.override.CustomButton', {
override : 'Ext.Button',
doTap: function(me, e) {
if(this.delayedTask == null){
this.callOverridden(arguments);
this.delayedTask = Ext.create('Ext.util.DelayedTask', function() {
this.delayedTask = null;
}, this);
this.delayedTask.delay(500);
} else {
console.log("Preventing double tap");
}
}
});
How does it works?
Each button action will trigger a delayedTask which will intercept button action for 500 ms, therefore preventing doubletap
This will work for 'tap' and 'handler:', which both pass through 'doTap' method
this is linked to the current button so it won't reverberate on other buttons
To use it simply add it in your app.js 'requires' block
Ext.application({
requires: [
...
'MyApp.override.CustomButton',
...
],
Helpfull Sources :
https://www.sencha.com/forum/showthread.php?173374-Ext-override()-on-Ext-components-in-ExtJS-4-x
Best practice for overriding classes / properties in ExtJS?
this post