AVPlayer seekToTime заставляет игрока прекращать воспроизведение

У меня есть AVPlayer, который транслирует радиостанцию ​​и имеет встроенную кнопку перемотки. При перемотке назад метод вызывается и РАБОТАЕТ около 80% времени, успешно устанавливая текущее время AVPLayer назад на X-много секунд. Однако в остальных 20% случаев AVPlayer прекращает воспроизведение звука и не будет воспроизводить его снова, пока приложение не будет убито и повторно открыто. Вот метод:

- (IBAction)rewind:(id)sender
{
    CMTime cmTime = CMTimeMake(CMTimeGetSeconds(self.player.currentTime) - 1.0, 1);
    CMTime almostZero = CMTimeMake(1, 2);
    if (CMTimeGetSeconds(cmTime) > CMTimeGetSeconds(almostZero)) {
    [self.player.currentItem seekToTime:cmTime];
    }
}

Для контекста это прямой эфир.

Вот мой метод 15-секундной перемотки:

 if((self.currentPlaybackTime - 15.0f) > CMTimeGetSeconds(kCMTimeZero)) {
        [self.player pause];
        [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 15.0f), self.player.currentTime.timescale)];
        [self.player play];
        } else if((self.currentPlaybackTime - 10.0f) > CMTimeGetSeconds(kCMTimeZero)) {
       [self.player pause];
       [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 10.0f), self.player.currentTime.timescale)];
            [self.player play];
    } else if((self.currentPlaybackTime - 5.0f) > CMTimeGetSeconds(kCMTimeZero)) {
        [self.player pause];
        [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 5.0f), self.player.currentTime.timescale)];
        [self.player play];

    } else if((self.currentPlaybackTime - 3.0f) > CMTimeGetSeconds(kCMTimeZero)) {
        [self.player pause];
        [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 3.0f), self.player.currentTime.timescale)];
        [self.player play];
    } else if((self.currentPlaybackTime - 2.0f) > CMTimeGetSeconds(kCMTimeZero)) {
       [self.player pause];
       [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 2.0f), self.player.currentTime.timescale)];
        [self.player play];
    } else if((self.currentPlaybackTime - 1.0f) > CMTimeGetSeconds(kCMTimeZero)) {
        [self.player pause];
        [self.player seekToTime:CMTimeMakeWithSeconds((self.currentPlaybackTime - 1.0f), self.player.currentTime.timescale)];
        [self.player play];
    }

- (NSTimeInterval)currentPlaybackTime
{
    return CMTimeGetSeconds(self.player.currentTime);
}

Когда я зарегистрировал метод и секунды, вы можете увидеть, что при третьей перемотке (при которой звук всегда останавливается и не перезапускается) проигрыватель на самом деле не вернулся на 15 секунд, хотя кажется, что seekToTime соответствует текущему времени. минус 15 секунд проработало.

2015-05-28 09:34:57.383 Lancers[78554:11732524] sec: 45
2015-05-28 09:34:58.382 Lancers[78554:11732524] sec: 46
2015-05-28 09:34:59.383 Lancers[78554:11732524] sec: 47
2015-05-28 09:35:00.383 Lancers[78554:11732524] sec: 48
2015-05-28 09:35:01.382 Lancers[78554:11732524] sec: 49
2015-05-28 09:35:02.237 Lancers[78554:11732524] CURRENT PLAYING TIME: 49.855237
2015-05-28 09:35:02.237 Lancers[78554:11732524] REWIND 15 SECONDS!
2015-05-28 09:35:02.293 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:02.293 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:02.305 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:02.305 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:02.305 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:02.472 Lancers[78554:11732524] sec: 35
2015-05-28 09:35:03.472 Lancers[78554:11732524] sec: 36
2015-05-28 09:35:04.473 Lancers[78554:11732524] sec: 37
2015-05-28 09:35:05.473 Lancers[78554:11732524] sec: 38
2015-05-28 09:35:06.473 Lancers[78554:11732524] sec: 39
2015-05-28 09:35:07.472 Lancers[78554:11732524] sec: 40
2015-05-28 09:35:08.473 Lancers[78554:11732524] sec: 41
2015-05-28 09:35:09.473 Lancers[78554:11732524] sec: 42
2015-05-28 09:35:10.473 Lancers[78554:11732524] sec: 43
2015-05-28 09:35:11.472 Lancers[78554:11732524] sec: 44
2015-05-28 09:35:12.472 Lancers[78554:11732524] sec: 45
2015-05-28 09:35:13.472 Lancers[78554:11732524] sec: 46
2015-05-28 09:35:13.771 Lancers[78554:11732524] CURRENT PLAYING TIME: 46.299634
2015-05-28 09:35:13.771 Lancers[78554:11732524] REWIND 15 SECONDS!
2015-05-28 09:35:13.821 Lancers[78554:11732524] sec: 31
2015-05-28 09:35:13.821 Lancers[78554:11732524] sec: 31
2015-05-28 09:35:13.833 Lancers[78554:11732524] sec: 31
2015-05-28 09:35:13.833 Lancers[78554:11732524] sec: 31
2015-05-28 09:35:13.833 Lancers[78554:11732524] sec: 31
2015-05-28 09:35:14.557 Lancers[78554:11732524] sec: 32
2015-05-28 09:35:15.557 Lancers[78554:11732524] sec: 33
2015-05-28 09:35:16.556 Lancers[78554:11732524] sec: 34
2015-05-28 09:35:16.870 Lancers[78554:11732524] CURRENT PLAYING TIME: 34.314164
2015-05-28 09:35:16.870 Lancers[78554:11732524] REWIND 15 SECONDS!
2015-05-28 09:35:16.898 Lancers[78554:11732524] sec: 34
2015-05-28 09:35:16.899 Lancers[78554:11732524] sec: 34

person Jameson    schedule 27.05.2015    source источник
comment
Если у вас есть подход, который работает, в чем вопрос?   -  person matt    schedule 27.05.2015
comment
Это не так. Кнопка перемотки срабатывает дважды, затем звук останавливается. Можно только 30 секунд перематывать, потом плеер зависает. Если я скажу методу rewind2 просто вызвать метод rewind1 15 раз, проигрыватель все равно зависнет при третьем вызове.   -  person Jameson    schedule 27.05.2015
comment
Я не понимаю, что значит зависания. Если вы хотите возобновить игру после поиска, поможет ли вам вместо этого позвонить seekToTime:toleranceBefore:toleranceAfter:completionHandler:? Весь смысл completionHandler: в том, что вы можете делать что-то вроде игры после поиска.   -  person matt    schedule 27.05.2015
comment
Спасибо. На что мне установить допуск? Когда я ищу с помощью метода rewind1, он продолжает играть, поэтому я решил, что он всегда продолжает играть после того, как вы ищете.   -  person Jameson    schedule 27.05.2015
comment
Не знаю, но в документации сказано, что это наиболее точно. Я не говорю, что это сработает, но было бы неплохо, если бы это сработало! Попробуйте и посмотрим, что из этого получится ...   -  person matt    schedule 27.05.2015
comment
Кроме того, меня немного смущает ваш код; ты понимаешь, как работает CMTimeMake? Возможно, вы просто указываете неверное время. См. Мое обсуждение здесь stackoverflow.com/a/23229197/341994 (и обязательно посмотрите мой ответ и мои комментарии под этим).   -  person matt    schedule 27.05.2015
comment
Если вам все еще интересно, смотрите обновление в моем вопросе. Кажется, использование seekToTime:toleranceBefore:toleranceAfter:completionHandler: вместо этого тоже не сработало.   -  person Jameson    schedule 27.05.2015
comment
Отлично, спасибо, я проверю это.   -  person Jameson    schedule 27.05.2015
comment
Я также почти уверен, что мои времена действительны. Метод работает правильно дважды (переходит к правильному CMTime, которое является текущим временем минус 15 секунд), затем всегда в третий раз, когда игрок прекращает играть, и ничто не заставит его снова играть. Если время неверно, почему он будет работать дважды, а затем потерпеть неудачу?   -  person Jameson    schedule 27.05.2015


Ответы (1)


Я догадываюсь о вашем приложении, но думаю, что проблема может быть в буферизации потокового аудио. Я много раз использовал AVPlayer с локальными носителями, и у меня никогда не было проблем с seekToTime.

Переход к неверному времени может вас испортить, но, судя по тому, что я вижу в вашем коде, с вами все должно быть в порядке. Ваш код перемотки пытается вернуться на 1 секунду (а не на 15?), Если вы не находитесь в пределах 1/2 секунды от начала, и в этом случае вы не ищите и продолжаете играть.

Я бы проверил статус объекта AVPlayer (player.status, player.error) в методе перемотки и посмотрел, что происходит, когда вы вызываете seekToTime. Также проверьте значения и флаги состояния вашей переменной cmTime с помощью отладчика или NSLog, чтобы убедиться, что вы тоже в этом разбираетесь.

person Dan Loughney    schedule 27.05.2015
comment
У меня есть два отдельных метода перемотки: один на 15, а другой на 1 секунду. Я раньше не использовал AVPlayer, поэтому не совсем уверен, как реализовать ваше предложение, но, тем не менее, я ценю его и постараюсь изо всех сил. Что-то такое простое должно сработать, не так ли? NSLog(@"ERROR: %@", self.player.error); NSLog(@"STATUS: %d", self.player.status); - person Jameson; 28.05.2015
comment
Хм, я получил Error = NULL и Status = 1, независимо от того, перематывалась ли она успешно или заставляла игрока останавливаться. Кнопка по-прежнему работает даже после того, как игрок прекращает играть, и в этом случае я все еще получаю error = NULL и status = 1. - person Jameson; 28.05.2015
comment
OK. Устранение возможных проблем. Да, вы правильно регистрируете. А как насчет предложения @matt посмотреть значения cmTime в методе. Может, после второго расчета cmTime что-то пошло не так. Можете ли вы опубликовать код для корректировки -15 секунд, чтобы мы могли видеть выполняющийся код, который вызывает проблему? спасибо - dcl - person Dan Loughney; 28.05.2015
comment
ОК, выложил 15-секундный метод перемотки. Он в основном перематывает назад так же, как и вышеупомянутый метод, за исключением набора if-clauses, так что он будет перематывать назад до 0 или 1, если у вас текущее время меньше 15 секунд. - person Jameson; 28.05.2015
comment
OK. Я думаю, вот что происходит. К сожалению, если я прав, ваш код никогда не должен работать. То, что это иногда работает, может быть просто временем внутренней работы AVPlayer. AVPlayer.currentTime возвращает текущее время, только если вы играете. Если остановлено, то currentTime возвращает время начала для мультимедиа. Итак, после вызова [self.player pause] значение, которое вы получаете обратно от currentPlaybackTime, не то, что вы думаете. Сохраните currentTime перед тем, как сделать паузу, и выполните расчет seekToTime с этим значением. - person Dan Loughney; 28.05.2015
comment
Я ни разу особо не видел программ с возможностью перемотки прямой трансляции - как вы думаете, почему? И как ни странно, когда я удаляю [self.player pause], а также [self.player play], окружающие метод seekToTime:, абсолютно ничего не меняется. Вы думаете, что это невозможно сделать? К счастью, я решил проблему быстрой перемотки, создав синглтон NSDate, который точно отслеживает, как долго проигрыватель ведет потоковую передачу, но эта функция перемотки занимает у меня почти целую неделю. - person Jameson; 28.05.2015
comment
Я уверен, ты сможешь это сделать. Пока вы храните потоковые данные в буфере где-то в AVPlayer, это на самом деле не потоковая передача. - person Dan Loughney; 28.05.2015
comment
Можете ли вы предложить какие-либо ссылки о том, как мне лучше всего это сделать? Спасибо. - person Jameson; 28.05.2015
comment
Похоже, у вас уже есть данные, поступающие в ваше приложение и играющие - это большой шаг. Подумайте, что это за данные и где они проходят через ваше приложение. Таким образом, вы сможете определить, где лучше всего его кэшировать, сколько вы хотите хранить и как долго. Это должно определять, сохраните ли вы его в локальном файле, в основных данных и т. Д. - person Dan Loughney; 29.05.2015