There is a way to specify the time delay between audio tracks on the same playlist? - flutter

I need to set a specific time delay between audio tracks on the playlist. Ex. 10 seconds delay. How could I achieve this?. Thanks in advance

There are two ways:
Create a silent audio track of the desired duration and insert it between each item in your ConcatenatingAudioSource.
Don't use ConcatenatingAudioSource, write your own playlist logic.
An example of the second approach could be:
// Maintain your own playlist position
int index = 0;
// Define your tracks
final tracks = <IndexedAudioSource>[ ... ];
// Auto advance with a delay when the current track completes
player.processingStateStream.listen((state) async {
if (state == ProcessingState.completed && index < tracks.length) {
await Future.delayed(Duration(seconds: 10));
// You might want to check if another skip happened during our sleep
// before we execute this skip.
skipToIndex(index + 1);
}
});
// Make this a method so that you can wire up UI buttons to skip on demand.
Future<void> skipToIndex(int i) {
index = i;
await player.setAudioSource(tracks[index]);
}

Related

How to get audio duration with audio_service?

I am using audio_service to play mp3 file. I am following example_playlist as AudioPlayerHander. My code is exactly same as example. But I use dependency injection (get_It) rather than a global variable. And I replace with broadcast media item changes in _init() method to get duration.
Rx.combineLatest5<int?, List<MediaItem>, bool, List<int>?, Duration?,
MediaItem?>(
_player.currentIndexStream,
queue,
_player.shuffleModeEnabledStream,
_player.shuffleIndicesStream,
_player.durationStream, // <- add listening to durationStream here
(index, queue, shuffleModeEnabled, shuffleIndices, duration) {
if (kDebugMode) {
print("${mediaItem.value?.title} - $duration");
}
final queueIndex =
getQueueIndex(index, shuffleModeEnabled, shuffleIndices);
return (queueIndex != null && queueIndex < queue.length)
? queue[queueIndex].copyWith(
duration: duration) // <- sink mediaItem provided with duration
: null;
}).whereType<MediaItem>().distinct().listen(mediaItem.add);
But I did not get the duration correctly.
For playlist 1, it is upload in _init() method and first track's duration is showing correctly but if you click second track, duration is still showing first track's duration.
I have added Load Play List 2 button and load playlist 2. All track's duration is always zero.
Note: audio is playing and start progress from 0 if duration is zero.
If I added playlist 2 in audio_service's example_playlist, it is showing correctly.
So the only different is using global variable and dependency injection (getIt).
I have added sample Github project audio_service_playlist_test
May I know which path is missing?

What would be the best way to implement video ads for a Flutter app?

Currently making a video storage and streaming application. Right now I am trying to add ads to the application. What would be the best way to facilitate video ads for the app? I know that there is a google_mobile_ads package, but due to the guidelines of AdMob, I cannot show multiple video ads in a row. I would like to do something similar to YouTube where a series of 2 ads are shown to the user (in my case, 1 ad for every 30 minutes of content).
What you can do is, when video starts get total video duration and determine how often you want to show ad. Then using a listener keep track of current position and show ad time to time. I have done something like this:
int adEvery = 0;
List<int> adIntervalSeconds = []; //timestamps at which ad will be shown
bool throttle = false;
videoPlayerController.addListener(() {
int durationInSec = chewieController!.videoPlayerController.value.duration.inSeconds;
int positionInSec = chewieController!.videoPlayerController.value.position.inSeconds;
//1500 sec = 25 minutes, isDurationLoaded bool used to make sure it run just once.
if (durationInSec > 1500 && isDurationLoaded == false) {
isDurationLoaded = true;
//if duration > 25 mins then show ad every 20 mins approx.
totalAds = (durationInSec ~/ 1200).toInt();
adEvery = (durationInSec ~/ totalAds).toInt();
//get timestamps in seconds list at which ad should be shown
for (int i = 1; i < totalAds; i++) {
adIntervalSeconds.add(adEvery * i);
}
}
if (videoPlayerController.value.isPlaying &&
adIntervalSeconds.isNotEmpty &&
adIntervalSeconds.contains(positionInSec) &&
throttle == false) {
throttle = true;
Future.delayed(const Duration(seconds: 2), () {
throttle = false;
});
adIntervalSeconds.remove(positionInSec);
showInterstitial();
}
}
This is what I came up with.

Counter and call duration combination in flutter

int score = 0;
score += 1;
I wish to add 1 (+= 1) to score when call duration reach 30 seconds just once and reset the score to 0 when call duration is less than 30 seconds.
Text('$score')
and show it like this
import 'package:permission_handler/permission_handler.dart';
import 'package:call_log/call_log.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
I have imported 3 packages above
void callLogs() async {
Iterable<CallLogEntry> entries = await CallLog.get();
for (var item in entries) {
print(Duration()); <--- Use Duration & if statement to solve but duration not printing
}
}
and code I wrote above is not working as I imagined to even start with. What changes can I make for adding and resetting score to work? Please help and thanks in advance
Your code waits for this call to complete so it never runs anything under it:
Iterable<CallLogEntry> entries = await CallLog.get();
You could use the StopWatch object to get the time:
void callLogs() async {
Stopwatch stopwatch = new Stopwatch()..start();
Iterable<CallLogEntry> entries = await CallLog.get();
for (var item in entries) {
var duration = stopwatch.elapsed;
print('Duration $duration');
}
}
And use setState() to set score:
setState(() { duration > 30 ? score += 1 : score = 0 });
if you variable score is inside of a widget or in the build method then i think that it set it to the begin value any time you run setState because setState builds the build again and also the widgets that is inside the build.
if that is so then try to make the variable global.
PS: global means that you the variable is outside of your class.

Is there a way for Flutter's Timer.periodic to wait for a function return plus a fixed duration before moving to the next cycle?

I use Timer.periodic with a duration normally. This works perfectly for my current use case.
Duration fiveSecs = const Duration(seconds: 5);
new Timer.periodic(fiveSecs, checkChange);
void checkChange(Timer timer) async {
//do some network calls
}
In this particular case I make network calls that take no longer than 500ms, and doing them every 5 seconds is enough for whatever depends on what those calls return.
Now I want to check for new values as frequently as 2 seconds, however, based on what needs to be checked a network call could take anywhere from a few hundred milliseconds to even 10 seconds. I could give a large margin and use a frequency of like 20 seconds for the timer, but in this case I would even prefer a 1 second frequency if possible.
So is there a way the timer could wait for a function, and still have a fixed duration like 1 second. So the maximum time it would take would be 1 second + callback runtime? Or is there a better way this could be achieved, I'm open to suggestions. Thank you.
void startTimer() {
_timer = Timer.periodic(Duration(seconds: 1), (Timer t) async {
print("lets wait for 5 seconds");
_timer.cancel();
await Future.delayed(Duration(seconds: 5));
print("Job is done");
print(DateTime.now());
print("Do it again");
startTimer();
});
}
I have encountered the same situation lately,
what I did was (in my case inside a static class) to add a static boolean value and toggle it accoding to my situation needs, later checking it's value inside the Timer.Periodic callback.
Timer.periodic(ConstantValues.socketTimerOperationDelay, (Timer t) async{
if(_udpHandlerCompleted){
_udpHandlerCompleted = false;
if(!_shouldSendBroadcast || _shutDown)
t.cancel();
else
_writeAllToUdpSocket(_udpSocket, data, ConstantValues.udpMulticastGroup, ConstantValues.udpMulticastPort);
_udpHandlerCompleted = true;
}
});
As you can see in my situation, I had to wait for the callback to end before I move to the next one, I believe this is what you're looking for, but in case you need to await for a different method the solution would be similar,
simply toggle the boolean _udpHandlerCompleted (in my case) in the other function.
Edit:
If my soultion helped you, kindly mark it as the accepted answer. Good luck!
At the end checkChange add Future.delayed(const Duration(seconds: 5), checkChange) then call it once instead of running the timer. You can add/check a boolean flag if you need to kill it at any point.

Knowing when I can skip to any point in an audio file without buffering / delay in playback

I'm loading an MP3 on my webpage using audio = new Audio(). But I'd like to know that when setting audio.currentTime, the audio can skip to any point in the file -near the end or wherever -without any delay in playback. Ie I want to know when the MP3 has downloaded in its entirety.
Can I use the Audio object/element for this, or must I use an AudioContext as shown here?
Every AudioElement is exposing its buffered data as a TimeRanges object. TimeRanges is an object which tells you how many continuous parts aka ranges are already buffered. It does also have getters which return the respective start and end of each range in seconds.
In case your AudioElement is named audio the following code snippet will log the buffered time ranges at a given point in time.
const numberOfRanges = audio.buffered.length;
for (let i = 0; i < numberOfRanges; i += 1) {
console.log(
audio.buffered.start(i),
audio.buffered.end(i)
);
}
If you want to detect the point in time at which all data is buffered you could use a check similar to this one:
const isBufferedCompletely = (audio.buffered.length === 1
&& audio.buffered.start(0) === 0
&& audio.buffered.end(0) === audio.duration);
I used the Gist referenced in the comments below to construct an example. The following snippet will periodically check if the file is already buffered. It will log a message to the console once that is the case. I tested it on Chrome (v74) and Firefox (v66) on OS X. Please note that the file can't be played at the same time as the script will set the currentTime of the Audio Element.
const audio = new Audio('http://www.obamadownloads.com/mp3s/charleston-eulogy-speech.mp3');
audio.preload = 'auto';
function detectBuffered(duration) {
// Stick with the duration once it is known because it might get updated
// when reaching the end of the file.
if (duration === undefined && !isNaN(audio.duration)) {
duration = audio.duration;
}
const isBufferedCompletely = (audio.buffered.length === 1
&& audio.buffered.start(0) === 0
&& audio.buffered.end(0) === duration);
if (isBufferedCompletely) {
const seconds = Math.round(duration);
console.log('The complete file is buffered.');
console.log(`It is about ${ seconds } seconds long.`);
} else {
// Move the playhead of the audio element to get the browser to load
// the complete file.
if (audio.buffered.length > 0) {
audio.currentTime = Math.max(0, audio.buffered.end(0) - 1);
}
setTimeout(detectBuffered, 100, duration);
}
}
detectBuffered();