Since I encountered this issue and the previous answer is not complete (doesn't cover live stream case) - here is my improvement on top of it:
if ([keyPath isEqual:@"tracks"])
{
BOOL hasVideoTrack = NO;
for (AVPlayerItemTrack* track in [[yourPlayer.currentItem] tracks])
{
if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo])
{
hasVideoTrack = YES;
break;
}
}
if (hasVideoTrack)
{
} else {
}
}
Do note - this however will only let you show a local Audio only screen.
When playing a live stream - the Artwork for the audio only is supposed to come from the stream, so my code is more towards this:
if ([keyPath isEqualToString:@"timedMetadata"] == YES){
for (AVMetadataItem *metadata in self.player.currentItem.timedMetadata) {
if ([[metadata commonKey] isEqualToString:@"artwork"]) {
UIImage *overlayImage = [UIImage imageWithData:metadata.dataValue];
UIImageView *overlayImageView = [[UIImageView alloc] initWithImage:overlayImage];
overlayImageView.contentMode = UIViewContentModeScaleAspectFit;
[self hideAudioOnlySlide];
self.audioOnlyView = overlayImageView;
[self showAudioOnlySlide];
self.audioOnlyView.size = _playerView.size;
break;
}
}
}else if ([keyPath isEqualToString:@"tracks"] == YES){
NSArray *tracks = self.player.currentItem.tracks;
if ([self.player.currentItem hasVideoTracks] == NO) {
BOOL hasAudioOnlyFromStream = NO;
for (AVMetadataItem *metadata in self.player.currentItem.timedMetadata) {
if ([[metadata commonKey] isEqualToString:@"artwork"]) {
hasAudioOnlyFromStream = YES;
break;
}
}
if (hasAudioOnlyFromStream == NO) {
[self showAudioOnlySlide];
}
} else {
[self hideAudioOnlySlide];
}
}
Add observation code:
[item addObserver:self forKeyPath:@"timedMetadata" options:0 context:NULL];
[item addObserver:self forKeyPath:@"tracks" options:0 context:NULL];
Remove observation code:
@try {
[item removeObserver:self forKeyPath:@"timedMetadata"];
[item removeObserver:self forKeyPath:@"tracks"];
}
hasVideoTracks code (Inside a category over AVPlayerItem):
- (BOOL)hasVideoTracks{
BOOL hasVideoTracks = NO;
for (AVPlayerItemTrack* track in [self tracks]){
if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]){
hasVideoTracks = YES;
break;
}
}
return hasVideoTracks;
}
Note:
- DON'T use presentationSize to detect audio only - in iOS 7 it no longer becomes CGSizeZero when moving to audio only - but gives some funky sizes instead. It's not a reliable method.
- Show/Hide audioOnlySlide is pretty straight forward and should contain your implementation.