diff --git a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java index 5adf351f0..2e4b0803e 100644 --- a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java +++ b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java @@ -16,6 +16,7 @@ import com.google.android.exoplayer2.LivePlaybackSpeedControl; import com.google.android.exoplayer2.LoadControl; import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; @@ -86,6 +87,7 @@ public class AudioPlayer implements MethodCallHandler, Player.Listener, Metadata private Map mediaSources = new HashMap(); private IcyInfo icyInfo; private IcyHeaders icyHeaders; + private MediaMetadata mediaMetadata; private int errorCount; private AudioAttributes pendingAudioAttributes; private LoadControl loadControl; @@ -211,6 +213,12 @@ public void onAudioSessionIdChanged(int audioSessionId) { broadcastPendingPlaybackEvent(); } + @Override + public void onMediaMetadataChanged(MediaMetadata _mediaMetadata) { + mediaMetadata = _mediaMetadata; + broadcastImmediatePlaybackEvent(); + } + @Override public void onMetadata(Metadata metadata) { for (int i = 0; i < metadata.length(); i++) { @@ -872,10 +880,16 @@ private void broadcastImmediatePlaybackEvent() { private Map collectIcyMetadata() { final Map icyData = new HashMap<>(); - if (icyInfo != null) { + if (icyInfo != null || mediaMetadata != null) { final Map info = new HashMap<>(); - info.put("title", icyInfo.title); - info.put("url", icyInfo.url); + if (icyInfo != null) { + info.put("title", icyInfo.title); + info.put("url", icyInfo.url); + } + if (mediaMetadata != null) { + info.put("title", mediaMetadata.title != null ? mediaMetadata.title.toString() : null); + info.put("artist", mediaMetadata.artist != null ? mediaMetadata.artist.toString() : null); + } icyData.put("info", info); } if (icyHeaders != null) { diff --git a/just_audio/darwin/Classes/AudioPlayer.m b/just_audio/darwin/Classes/AudioPlayer.m index d22719d01..9cb561482 100644 --- a/just_audio/darwin/Classes/AudioPlayer.m +++ b/just_audio/darwin/Classes/AudioPlayer.m @@ -420,6 +420,7 @@ - (void)metadataOutput:(AVPlayerItemMetadataOutput *)output didOutputTimedMetada // ICY headers aren't available here. Maybe do this in the proxy. BOOL hasIcyData = NO; NSString *title = (NSString *)[NSNull null]; + NSString *artist = (NSString *)[NSNull null]; NSString *url = (NSString *)[NSNull null]; for (int i = 0; i < groups.count; i++) { AVTimedMetadataGroup *group = groups[i]; @@ -431,6 +432,12 @@ - (void)metadataOutput:(AVPlayerItemMetadataOutput *)output didOutputTimedMetada } else if ([@"icy/StreamUrl" isEqualToString:item.identifier]) { hasIcyData = YES; url = (NSString *)item.value; + } else if ([@"id3/TIT2" isEqualToString:item.identifier]) { + hasIcyData = YES; + title = (NSString *)item.value; + } else if ([@"id3/TPE1" isEqualToString:item.identifier]) { + hasIcyData = YES; + artist = (NSString *)item.value; } } } @@ -438,6 +445,7 @@ - (void)metadataOutput:(AVPlayerItemMetadataOutput *)output didOutputTimedMetada _icyMetadata = @{ @"info": @{ @"title": title, + @"artist": artist, @"url": url, }, }; diff --git a/just_audio/lib/just_audio.dart b/just_audio/lib/just_audio.dart index 591fcf781..4c1fe8562 100644 --- a/just_audio/lib/just_audio.dart +++ b/just_audio/lib/just_audio.dart @@ -1719,26 +1719,29 @@ class PlayerState { class IcyInfo { final String? title; + final String? artist; final String? url; static IcyInfo _fromMessage(IcyInfoMessage message) => IcyInfo( title: message.title, + artist: message.artist, url: message.url, ); - IcyInfo({required this.title, required this.url}); + IcyInfo({required this.title, required this.artist, required this.url}); @override - String toString() => 'title=$title,url=$url'; + String toString() => 'title=$title,artist=$artist,url=$url'; @override - int get hashCode => Object.hash(title, url); + int get hashCode => Object.hash(title, artist, url); @override bool operator ==(Object other) => other.runtimeType == runtimeType && other is IcyInfo && other.title == title && + other.artist == artist && other.url == url; } diff --git a/just_audio/test/just_audio_test.dart b/just_audio/test/just_audio_test.dart index 6b67812d1..daa703274 100644 --- a/just_audio/test/just_audio_test.dart +++ b/just_audio/test/just_audio_test.dart @@ -1420,6 +1420,7 @@ final icyMetadata = IcyMetadata( ), info: IcyInfo( title: 'title', + artist: 'artist', url: 'url', ), ); @@ -1435,6 +1436,7 @@ final icyMetadataMessage = IcyMetadataMessage( ), info: IcyInfoMessage( title: 'title', + artist: 'artist', url: 'url', ), ); @@ -1654,6 +1656,7 @@ class MockAudioPlayer extends AudioPlayerPlatform { ), info: IcyInfoMessage( title: 'title', + artist: 'artist', url: url, ), ), diff --git a/just_audio_platform_interface/CHANGELOG.md b/just_audio_platform_interface/CHANGELOG.md index c73ea3d9c..437ef5b7c 100644 --- a/just_audio_platform_interface/CHANGELOG.md +++ b/just_audio_platform_interface/CHANGELOG.md @@ -9,7 +9,8 @@ ## 4.2.1 -* Update minimum flutter version to 3.0. +- Added support for HLS title and artist metadata. +- Update minimum flutter version to 3.0. ## 4.2.0 diff --git a/just_audio_platform_interface/lib/just_audio_platform_interface.dart b/just_audio_platform_interface/lib/just_audio_platform_interface.dart index 3c9dbfcdb..4e05740d9 100644 --- a/just_audio_platform_interface/lib/just_audio_platform_interface.dart +++ b/just_audio_platform_interface/lib/just_audio_platform_interface.dart @@ -355,15 +355,20 @@ class IcyMetadataMessage { /// Icy info communicated from the platform implementation. class IcyInfoMessage { final String? title; + final String? artist; final String? url; IcyInfoMessage({ required this.title, + required this.artist, required this.url, }); static IcyInfoMessage fromMap(Map json) => IcyInfoMessage( - title: json['title'] as String?, url: json['url'] as String?); + title: json['title'] as String?, + artist: json['artist'] as String?, + url: json['url'] as String?, + ); } /// Icy headers communicated from the platform implementation.