I'm creating a program that can, amoung other things, fade in and out music. The problem is that other threads/queues can pause the music, meaning that the fade in and out also need to not only pause, but hold off. I need to be able to pause the "timer" on a dispatch_after (because this is called when the music starts playing in order to tell it when to start fading out, which would need to be delayed if it was paused) and pause a queue itself (in order to pause a fade in or fade out WHILE they're fading in or out)
Here's the code (fadeIn and delayFadeOut are both called at the start of the program):
- (void) doFadeIn: (float) incriment to: (int) volume with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue{
dispatch_async(queue, ^{
double delayInSeconds = .1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, queue, ^(void){
thisplayer.volume = (thisplayer.volume + incriment) < volume ? thisplayer.volume + incriment : volume;
NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
if (thisplayer.volume < volume) {
[self doFadeIn:incriment to:volume with:thisplayer on:queue];
}
});
});
}
-(void) doDelayFadeOut: (float) incriment with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue
{
dispatch_async(queue, ^{
double delayInSeconds = .1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, queue, ^(void){
thisplayer.volume = (thisplayer.volume - incriment) > 0 ? thisplayer.volume - incriment : 0;
NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
if (thisplayer.volume > 0.0) {
[self doDelayFadeOut:incriment with:thisplayer on:queue];
}
});
});
}
-(void) fadeIn: (AVAudioPlayer*) dFade {
if (dFade == nil) {
return;
}
dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
dispatch_async( queue, ^(void){
if(dFade !=nil){
double incriment = ([self relativeVolume] / [self fadeIn]) / 10; //incriment per .1 seconds.
[self doFadeIn: incriment to: [self relativeVolume] with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
}
});
}
- (void) delayFadeOut: (AVAudioPlayer*) dFade { //d-fade should be independent of other threads
if (dFade == nil) {
return;
}
int timeRun = self.duration - self.fadeOut;
dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
dispatch_time_t mainPopTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeRun * NSEC_PER_SEC));
printf("test");
dispatch_after(mainPopTime, queue, ^(void){
if(dFade !=nil){
double incriment = ([dFade volume] / [self fadeOut])/10; //incriment per .1 seconds.
[self doDelayFadeOut:incriment with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
}
});
if (self.cueType == 2) {
[self callNext];
}
}
You can't pause / cancel when using a GCD queue. If you need that functionality (and in a lot of general cases even if you don't) you should be using the higher level API - NSOperationQueue .
You don't stop the queue. Instead, when the task that you dispatched starts executing, it needs to check its context and do the right thing (often: nothing) if the context has changed.
Dispatch queues are FIFO queues to which your application can submit tasks in the form of block objects. Dispatch queues execute tasks either serially or concurrently. Work submitted to dispatch queues executes on a pool of threads managed by the system.
A dispatch queue that executes tasks serially in first-in, first-out (FIFO) order. typealias dispatch_queue_concurrent_t. A dispatch queue that executes tasks concurrently and in any order, respecting any barriers that may be in place.
To your general question, the call is dispatch_suspend()
(along with dispatch_resume()
). This will prevent any new blocks on a particular queue from being scheduled. It will not have any impact on already-running blocks. If you want to pause a block already scheduled and running, it is up to your code to check some conditional and pause.
The key to understand when using this, though, is that there is nothing that can "pause the "timer" on a dispatch_after." If you say you want something to be dispatched after 1 second, it absolutely will be dispatched after 1 second. But "dispatch" does not mean "run." It means "put on a queue." If that queue is suspended, then the block will hang out until the queue is resumed. The thing to be careful about is that you don't want a bunch of fade blocks to accumulate on the queue. If they did, when you resume the queue they would all be scheduled back-to-back. Looking at your code, that probably won't happen, so this could work for you. Just keep in your mind that dispatch means "put on a queue." And non-suspended queues have their blocks scheduled in order.
For suspending queues/cancelling operations, you should use NSOperation
and NSOperationQueue
instead of GCD. See here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With