Closed puckey closed 3 years ago
Nice! That would work for ID3 and Quicktime Metadata, right?
I wonder how difficult would it be to implement ICY metadata too? There are a lot of users that want to build an app for their online radio. It's a pretty simple protocol but requires a custom HTTP stream decoder.
Yes, it seems to emit ICY metadata also - which is what I am looking to use it for.
That's perfect! I've just pushed to v2 Vorbis Comments and QuickTime Metadata support to Android https://github.com/react-native-kit/react-native-track-player/commit/4139370f83913b21e459ffd16611dc9ca9fbc4e4
@Guichaguri are you testing this with any specific files?
Also, I noticed icy metadata is always returned as title
with artist name and track name. The separator between can be whatever the station wants (I have seen asterisks used as separators) and also the order can be either artist/track
or track/artist
.. sometimes one or both are all-caps. It is a mess and I am not sure we should be attempting to clean it up by splitting the string on -
I made a pr for iOS support here: https://github.com/react-native-kit/react-native-track-player/pull/937
This emits the playback-metadata-received
event when a track with metadata is loaded and also emits them over time when listening to a stream.
I have yet to align things perfectly with the Android version. I was thinking it might help to define a set of source files which we can use to compare Android and iOS.
Meat and potatoes of iOS functionality is here: https://github.com/puckey/react-native-track-player/blob/bb330b675a7d9d692eb8c5fa2ec0984f19e0736e/ios/RNTrackPlayer/RNTrackPlayerAudioPlayer.swift#L83
@Guichaguri are you testing this with any specific files?
Also, I noticed icy metadata is always returned as
title
with artist name and track name. The separator between can be whatever the station wants (I have seen asterisks used as separators) and also the order can be eitherartist/track
ortrack/artist
.. sometimes one or both are all-caps. It is a mess and I am not sure we should be attempting to clean it up by splitting the string on-
Yeah, at first I thought splitting them would be a good idea, but we definitely should return just the full station title. As this is a breaking change we should do that in v2
Here are some implementation details on Android:
ICY
StreamTitle
StreamTitle
StreamUrl
ICY Headers
Icy-Name
Icy-Url
Icy-Genre
ID3 Another weird implementation, it actually tries to find the properties from a number of different tags, ideally it should only fetch one, but there is either no clear specification on which ones should be preferred or they are there for compatibility with older versions (e.g. ID3v1)
TIT2
or TT2
TALB
, TOAL
or TAL
TOPE
, TPE1
or TP1
TDRC
or TOR
TCON
or TCO
WOAS
, WOAF
, WOAR
or WAR
Vorbis Comments
TITLE
ARTIST
ALBUM
DATE
GENRE
URL
QuickTime Metadata
com.apple.quicktime.title
com.apple.quicktime.artist
com.apple.quicktime.album
com.apple.quicktime.creationdate
com.apple.quicktime.genre
Here is an overview of the AVMetadataIdentifier
types on ios: https://github.com/xybp888/iOS-SDKs/blob/master/iPhoneOS13.0.sdk/System/Library/Frameworks/AVFoundation.framework/Headers/AVMetadataIdentifiers.h
We can use the common types for most of what we are looking for:
AVMetadataIdentifier.commonIdentifierTitle
AVMetadataIdentifier.commonIdentifierArtist
AVMetadataIdentifier.commonIdentifierAlbumName
AVMetadataIdentifier.commonIdentifierCreationDate
ICY
AVMetadataKeySpace.common
AVMetadataIdentifier.commonIdentifierTitle
ICY Headers
Even though these identifiers exist, I have not seen a stream return ICY Headers
metadata values yet on iOS..
AVMetadataKeySpace.icy
AVMetadataIdentifier.icyMetadataStreamTitle
AVMetadataIdentifier.icyMetadataStreamURL
ID3
AVMetadataKeySpace.id3
AVMetadataIdentifier.id3MetadataContentType
(TCON
)TCO
is missingAVMetadataIdentifier.id3MetadataOfficialAudioSourceWebpage
(WOAS
) AVMetadataIdentifier.id3MetadataOfficialAudioFileWebpage
(WOAF
) AVMetadataIdentifier.id3MetadataOfficialArtistWebpage
(WOAR
)WAR
is missingQuickTime Metadata
AVMetadataIdentifier.quickTimeMetadataGenre
I finished off my PR incorporating the implementations details as described in the comment above: https://github.com/react-native-kit/react-native-track-player/pull/937
Coming back to this, it seems iOS 12 has started returning icy metadata as AVMetadataIdentifier.icyMetadataStreamTitle
, where it was using AVMetadataIdentifier.commonIdentifierTitle
before
@puckey , @guichaguri thank you for implementing the IOS side of the playback-metadata-received event handler. I will simplify my code and not use the platform detect if / then on andling and do straight up playnack-metadata-received handling. Also, on this, as we have several shoutcast stations (transmits ID3 and Icy headers) I noticed the reat-native-track-player does not seem to pick up two items: duration and position reset when songs change on the shoutcast station. I have tried third party web radio players as HTML widgets on our website which has no problems finding duration and resets position af each new song playing. Why isn't react-nativve-track-player working like this?
Another note, the industry standards for separator is " - " (one space, a dash, and one space). Those using '*" (askerisks are bending the standards... Even in Android, I have to collect the album, title and artist values from the RN Track-player and do some more JS processing to get the album / titles / artist right. Not sure if this is our Shoutcast provider or the RN Track-Player algorithm miss.
But thanks for getting the iOS playback-metadata-received in and will be testing it fairly soon.
Coming back to this, it seems iOS 12 has started returning icy metadata as
AVMetadataIdentifier.icyMetadataStreamTitle
, where it was usingAVMetadataIdentifier.commonIdentifierTitle
before
I just updated my app to use your changes and found the same. I decided to change the source = icy-headers
to just icy
and added the title split to the icy if
and now it is working exactly as expected (and as in android) :)
@dodgex could you share your changes in more detail? I would be happy to wrap this pr up and merge it
@puckey any news on this? :D
Hi, funny you mentioned the icy header and split on title. I wound up doing just this, but left the source code alone and just did it within player.js (see the react-native-track-player-example). Also, I noticed iOS 12 did solve the Icy issues so I removed the platform conditional within the metadata-received method also now in player.js. As far as issue #686 recommended code for the playerlistscreem on the togglePlayer function. I moved the metadata relevent portion to player.js added the use even (playback-metadata-received0 and the out of sync issue went away. I stll cannot solve the position and duration set and reset when a new song track is started from my shoutcast radiostations. Seems the use event for playback-metadata-receieed does not manage the position and duration and indicated in the library code I reviewed. Any idea what I should be using to trigger position and duration if it isn't the playback-metadata-received event isn't the correct method? Thanks for keeping me in the loop on this issue.
@BryonConley The metadata provided by shoutcast and icecast servers only contain StreamTitle and StreamUrl fields. so there is no information about position and duration.
actually those fields don't even make much sends on those services as those are mostly used in some kind of live broadcasting services where the dj has full controll over where in the song the playback starts and how long the track is actually played before the next on is mixed in (at least this is true for all usecases where i have seen a shout-/icecast server in use until now).
@puckey any news on this? :D
My work goes from frontend to backend to native in waves. Will be shifting back to this in a few weeks!
@dodgex Thanks for putting up your branch. Looking at this again, it seems AVMetadataIdentifier.commonIdentifierTitle
still works. It actually looks like the latest iOS is erroneously seeing the track title as .icyMetadataStreamTitle
, while this is ought to be reserved for the title of the stream. So it seems we end up with a mix between the title of icy
and the url of icy-headers
.. Ugh! For this reason I removed the title = getMetadataItem(forIdentifier: .icyMetadataStreamTitle)
part to avoid possible future breakages. See https://github.com/puckey/react-native-track-player/commit/0532000bb793f020a7676cc1ce2038613f98c78d
I think this is ready for merging. Let me know what you think.
I tested your changes on a iOS 14.1 simulator and it works. 👍
but I do not agree with this statement:
It actually looks like the latest iOS is erroneously seeing the track title as .icyMetadataStreamTitle, while this is ought to be reserved for the title of the stream
Icecast meta (icy
on-stream) only has two fields StreamTitle
(represented in .icyMetadataStreamTitle
) and StreamUrl
(represented in .icyMetadataStreamURL
. The Meta in the Header (icy-headers
) sent on connect there might be more data but for this use case the on-stream meta is what is interesting. And it seems that the iOS component here does not even process the icy-headers
.
The StreamTitle attribute is built depending on the data the server knows, when only a title is configured it is just that. but if there is an artist+title configured it becomes ' %s - %s'. official icecast: https://gitlab.xiph.org/xiph/icecast-server/-/blob/master/src/format_mp3.c#L284 icecast-kh fork: https://github.com/karlheyes/icecast-kh/blob/master/src/format_mp3.c#L495
so I'd say both is valid. :)
@puckey and others, just and FYI, we have radio servers that we can program the streamTitle more/or less fluidly on our Centova Cast. The stream are then fed to Shoutcast and there they form their own. When we point our apps to the CentovaCast, we get to make the stream title like this: %album% - %artist% - %title% . even still, we can program the album field to includ duration through string text tricks along with our App control tokens. For instance we can do MyBestAlbum:%duration% or even things like Promo:%MyBestAlbum: and make this the new %album% value as part of the custpm stream title. I'd like to try out the ios playback-metadata-received and what you have. Please let me know where I can get the swift source on the code. Thanks all for taking the time to review my request.
@BryonConley Yo! I'm currently developing an app for my station, and we're also using Centova Cast and shoutcast. For our mobile app, I'm using react-native-track-player. I'm having weird intermittent problems with the native controls and meta data though.. Any chance you could share a repo or give me a little insight to your implementation so far? 🙏
closing this as this has been added in v2
. See comment here: https://github.com/DoubleSymmetry/react-native-track-player/pull/937#issuecomment-850900859
It looks like this SwiftAudio pull-request is the first step to adding iOS support for 'playback-metadata-received': https://github.com/jorgenhenrichsen/SwiftAudio/pull/93
I have a hacked together version running locally and will see if I can flesh it out to match the functionality of the Android side.