AVPlayer progreso de transmisión

Estoy usando AVPlayer con AVPlayer para transmitir audio desde un servidor y lo que quiero hacer ahora es mostrar un UISlider personalizado que muestre el progreso del almacenamiento en búfer.

Algo como esto:

enter image description here

Con AVPlayer no parece haber una manera de obtener el tamaño de descarga total o la cantidad descargada actual para el archivo de audio, solo el tiempo de reproducción actual y el tiempo total de reproducción.

Hay alguna solución para esto?

Solo estoy trabajando en esto, y hasta ahora tengo lo siguiente:

 - (NSTimeInterval) availableDuration; { NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges]; CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue]; Float64 startSeconds = CMTimeGetSeconds(timeRange.start); Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval result = startSeconds + durationSeconds; return result; } 

Debería funcionar bien:

C objective:

 - (CMTime)availableDuration { NSValue *range = self.player.currentItem.loadedTimeRanges.firstObject; if (range != nil){ return CMTimeRangeGetEnd(range.CMTimeRangeValue); } return kCMTimeZero; } 

Versión Swift:

 func availableDuration() -> CMTime { if let range = self.player?.currentItem?.loadedTimeRanges.first { return CMTimeRangeGetEnd(range.timeRangeValue) } return kCMTimeZero } 

Para ver el valor de tiempo actual, puede usar: CMTimeShow ([self availableDuration]); o CMTimeShow (availableDuration ()) (para swift)

Personalmente, no estoy de acuerdo con que el valor de timeRanges siempre tenga un recuento de 1.

De acuerdo con la documentación

La matriz contiene objetos NSValue que contienen un valor CMTimeRange que indica los intervalos de tiempo para los cuales el elemento de jugador tiene datos de medios fácilmente disponibles. Los intervalos de tiempo devueltos pueden ser discontinuos.

Entonces esto puede tener valores similares a:

[(start1, end1), (start2, end2)]

Desde mi experiencia con el framework hls.js en el mundo web de escritorio, los agujeros entre estos rangos de tiempo podrían ser muy pequeños o grandes dependiendo de una multitud de factores, por ejemplo: búsqueda, discontinuidades, etc.

Para obtener correctamente la longitud total del búfer, necesitaría recorrer la matriz y obtener la duración de cada elemento y concat.

Si busca un valor de búfer del encabezado de reproducción actual, deberá filtrar los rangos de tiempo para una hora de inicio que sea mayor que la hora actual y una hora de finalización menor que la hora actual.

 public extension AVPlayerItem { public func totalBuffer() -> Double { return self.loadedTimeRanges .map({ $0.timeRangeValue }) .reduce(0, { acc, cur in return acc + CMTimeGetSeconds(cur.start) + CMTimeGetSeconds(cur.duration) }) } public func currentBuffer() -> Double { let currentTime = self.currentTime() guard let timeRange = self.loadedTimeRanges.map({ $0.timeRangeValue }) .first(where: { $0.containsTime(currentTime) }) else { return -1 } return CMTimeGetSeconds(timeRange.end) - currentTime.seconds } } 

Este método devolverá el intervalo de tiempo del búfer para su UISlider

 public var bufferAvail: NSTimeInterval { // Check if there is a player instance if ((player.currentItem) != nil) { // Get current AVPlayerItem var item: AVPlayerItem = player.currentItem if (item.status == AVPlayerItemStatus.ReadyToPlay) { var timeRangeArray: NSArray = item.loadedTimeRanges var aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue var startTime = CMTimeGetSeconds(aTimeRange.start) var loadedDuration = CMTimeGetSeconds(aTimeRange.duration) return (NSTimeInterval)(startTime + loadedDuration); } else { return(CMTimeGetSeconds(kCMTimeInvalid)) } } else { return(CMTimeGetSeconds(kCMTimeInvalid)) } } 

La respuesta seleccionada puede causarle problemas si la matriz devuelta está vacía. Aquí hay una función fija:

 - (NSTimeInterval) availableDuration { NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges]; if ([loadedTimeRanges count]) { CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue]; Float64 startSeconds = CMTimeGetSeconds(timeRange.start); Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration); NSTimeInterval result = startSeconds + durationSeconds; return result; } return 0; } 

El código de Suresh Kansujiya en Objective C

 NSTimeInterval bufferAvail; if (player.currentItem != nil) { AVPlayerItem *item = player.currentItem; if (item.status == AVPlayerStatusReadyToPlay) { NSArray *timeRangeArray = item.loadedTimeRanges; CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue]; Float64 startTime = CMTimeGetSeconds(aTimeRange.start); Float64 loadedDuration = CMTimeGetSeconds(aTimeRange.duration); bufferAvail = startTime + loadedDuration; NSLog(@"%@ - %f", [self class], bufferAvail); } else { NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); } } else { NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); }