X分钟后停止音频播放器

时间:2021-08-24 02:54:39

I'm working on an Audio App. One task that I must accomplish is to be able to stop the audio player after X minutes (defined by user), like a player sleep.

我正在制作音频应用程序。我必须完成的一项任务是能够在X分钟(由用户定义)之后停止音频播放器,就像玩家睡眠一样。

To do it, I use local notifications.

为此,我使用本地通知。

This is the code in my custom player:

这是我的自定义播放器中的代码:

- (void)configureSleepTimer:(NSUInteger)seconds {
    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:seconds];
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    localNotification.soundName = UILocalNotificationDefaultSoundName;

    NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:@[@"PlayerSleep"] forKeys:@[@"type"]];
    localNotification.userInfo = userInfo;

    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    NSLog(@"Notification: %@", localNotification);
}

AppDelegate:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    if ([[notification.userInfo valueForKey:@"type"] isEqualToString:@"PlayerSleep"]) {
        Player *player = [Player sharedInstance];
        [player stopPlayer];
    }
}

The problem with the above code, is that the player does not stops when the app is running in the background.

上述代码的问题在于,当应用程序在后台运行时,播放器不会停止。

To get this run in the background, I check when the app enters in background mode and check if exists local notifications. If exists, I fire a one second timer to compare notifications firetimes with real date to stop the player if needed.

为了在后台运行,我检查应用程序何时进入后台模式并检查是否存在本地通知。如果存在,我会启动一秒计时器,将通知消息时间与实际日期进行比较,以便在需要时停止播放器。

- (void)applicationDidEnterBackground:(UIApplication *)application {
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if ([[[UIApplication sharedApplication] scheduledLocalNotifications] count]) {
            NSTimer *t = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sleepPlayer) userInfo:nil repeats:YES];
            [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
            [[NSRunLoop currentRunLoop] run];
        }
    });
}

- (void)sleepPlayer {
    [[[UIApplication sharedApplication] scheduledLocalNotifications] enumerateObjectsUsingBlock:^(UILocalNotification *notification, NSUInteger idx, BOOL *stop) {
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"dd-MM-yyyy HH:mm:ss"];
        NSString *dateTimeStr = [formatter stringFromDate:[NSDate date]];
        NSString *notifDateStr = [formatter stringFromDate:[NSDate dateWithTimeInterval:-1 sinceDate:notification.fireDate]];

        if ([dateTimeStr isEqualToString:notifDateStr]) {
            Player *player = [Player sharedInstance];
            [player stopPlayer];
            [[UIApplication sharedApplication] cancelLocalNotification:notification];

            NSLog(@"************************** Player Sleeped");
        }
    }];
}

It works, but, I don't like this last piece of code. Is there a better way of doing it?

它有效,但是,我不喜欢这最后一段代码。有没有更好的方法呢?

1 个解决方案

#1


0  

Solution1. I have implemented something similar, but not the exact thing what you want. What I did was, when track finishes, check the sleep time, and if it's exceeded, stop the player, which was passive way of implementing sleep timer with player. Maybe, this solution will work for you too?

解决方法1。我已经实现了类似的东西,但不是你想要的东西。我做的是,当赛道结束时,检查睡眠时间,如果超过,则停止播放器,这是用玩家实现睡眠定时器的被动方式。也许,这个解决方案对你也有用吗?

Solution2. If your app supports background modes, i.e. it plays audio on the background, you can schedule timer (no need to begin background task) to be called on exact time with initWithFireDate: initialization method of NSTimer. Doing so, you timer won't be called every second, but on exact time.

溶液2。如果您的应用程序支持后台模式,即它在后台播放音频,您可以使用initWithFireDate:NSTimer的初始化方法在准确的时间调度计时器(无需开始后台任务)。这样做,您的计时器将不会每秒调用,但会在准确的时间调用。

Hope this was helpful. Good luck!

希望这很有帮助。祝好运!

P.S.: keep in mind, both solutions require your app to be registered for background modes, at least audio.

P.S。:请记住,两种解决方案都要求您的应用程序注册为背景模式,至少是音频。

#1


0  

Solution1. I have implemented something similar, but not the exact thing what you want. What I did was, when track finishes, check the sleep time, and if it's exceeded, stop the player, which was passive way of implementing sleep timer with player. Maybe, this solution will work for you too?

解决方法1。我已经实现了类似的东西,但不是你想要的东西。我做的是,当赛道结束时,检查睡眠时间,如果超过,则停止播放器,这是用玩家实现睡眠定时器的被动方式。也许,这个解决方案对你也有用吗?

Solution2. If your app supports background modes, i.e. it plays audio on the background, you can schedule timer (no need to begin background task) to be called on exact time with initWithFireDate: initialization method of NSTimer. Doing so, you timer won't be called every second, but on exact time.

溶液2。如果您的应用程序支持后台模式,即它在后台播放音频,您可以使用initWithFireDate:NSTimer的初始化方法在准确的时间调度计时器(无需开始后台任务)。这样做,您的计时器将不会每秒调用,但会在准确的时间调用。

Hope this was helpful. Good luck!

希望这很有帮助。祝好运!

P.S.: keep in mind, both solutions require your app to be registered for background modes, at least audio.

P.S。:请记住,两种解决方案都要求您的应用程序注册为背景模式,至少是音频。