Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for HLS title and artist metadata #745

Open
wants to merge 10 commits into
base: minor
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -86,6 +87,7 @@ public class AudioPlayer implements MethodCallHandler, Player.Listener, Metadata
private Map<String, MediaSource> mediaSources = new HashMap<String, MediaSource>();
private IcyInfo icyInfo;
private IcyHeaders icyHeaders;
private MediaMetadata mediaMetadata;
private int errorCount;
private AudioAttributes pendingAudioAttributes;
private LoadControl loadControl;
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -872,10 +880,16 @@ private void broadcastImmediatePlaybackEvent() {

private Map<String, Object> collectIcyMetadata() {
final Map<String, Object> icyData = new HashMap<>();
if (icyInfo != null) {
if (icyInfo != null || mediaMetadata != null) {
final Map<String, String> 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) {
Expand Down
8 changes: 8 additions & 0 deletions just_audio/darwin/Classes/AudioPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -431,13 +432,20 @@ - (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;
}
}
}
if (hasIcyData) {
_icyMetadata = @{
@"info": @{
@"title": title,
@"artist": artist,
@"url": url,
},
};
Expand Down
9 changes: 6 additions & 3 deletions just_audio/lib/just_audio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions just_audio/test/just_audio_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,7 @@ final icyMetadata = IcyMetadata(
),
info: IcyInfo(
title: 'title',
artist: 'artist',
url: 'url',
),
);
Expand All @@ -1435,6 +1436,7 @@ final icyMetadataMessage = IcyMetadataMessage(
),
info: IcyInfoMessage(
title: 'title',
artist: 'artist',
url: 'url',
),
);
Expand Down Expand Up @@ -1654,6 +1656,7 @@ class MockAudioPlayer extends AudioPlayerPlatform {
),
info: IcyInfoMessage(
title: 'title',
artist: 'artist',
url: url,
),
),
Expand Down
3 changes: 2 additions & 1 deletion just_audio_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<dynamic, dynamic> 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.
Expand Down