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

Support just-in-time resolution of URLs (using app logic) #5779

Closed
LowLevelSubmarine opened this issue Apr 18, 2019 · 5 comments
Closed

Support just-in-time resolution of URLs (using app logic) #5779

LowLevelSubmarine opened this issue Apr 18, 2019 · 5 comments
Assignees

Comments

@LowLevelSubmarine
Copy link

LowLevelSubmarine commented Apr 18, 2019

Searched documentation and issues

-This repository
-Web (medium, stackoverflow, etc.)

Question

I am developing an app, in which you can play songs from a website. Right now, parsing the url for the tracks takes some time (although I do cache) and doesn't always work flawlessly, but if it has been parsed I add it do the concatinating Media Source. The Problem lays within the playlist mechanichs. If I want to play a long playlist, I need to load them all at once into my concatenating media source. But most of the tracks in that long playlist wont get played. I thought that I could try implementing the part where I parse the songs url from the web, after the song has been queued rather an in advance. So that it will only get parsed when ExoPlayer starts buffering the actual Track.

I tried implementing MediaSource while just passing the method calls to an underlying ExtractorMediasource, but to be honest, I didn't know where to start, and what the methods ment, even after reading the docs.

TL;DR:

I'd like to implement my res hungry uri parsing for an ExtractorMediaSource after queueing to an ConcatinatingMediaSource (in this case sometimes rly long playlist). So that it will only get parsed when the user really wants to hear that song. If someone knew where I could start looking or if there was a simpler way to implement this than creating my own MediaSource implementation, would help me A LOT!

Thx in advance. I hope my english is at least a bit understandable.

@ojw28
Copy link
Contributor

ojw28 commented Apr 22, 2019

Just-in-time resolution of URLs has been asked for elsewhere as well. We should probably look at supporting it for all stream types (Progressive/DASH/SS/HLS).

@ojw28 ojw28 changed the title Uri parsing after queueing Support just-in-time resolution of URLs for MediaSources (using app provided logic) Apr 22, 2019
@ojw28 ojw28 changed the title Support just-in-time resolution of URLs for MediaSources (using app provided logic) Support just-in-time resolution of URLs (using app provided logic) Apr 22, 2019
@ojw28 ojw28 changed the title Support just-in-time resolution of URLs (using app provided logic) Support just-in-time resolution of URLs (using app logic) Apr 22, 2019
@Jonbeckas
Copy link

I have the same problem, and I need to fix it very quickly. When can I expect this feature to be implemented? Its totally ok if you dont have priority on such little enhancements. I'd just like to know if I should try implementing it for myself.

@ojw28
Copy link
Contributor

ojw28 commented May 6, 2019

One fairly straightforward approach that you can use in the meantime is to use dummy URIs that contain the information needed to resolve the real URL. For example if you need the video id, you could use a scheme like: app://video_id. Then make a custom DataSource (and DataSource.Factory) that resolves the URIs to URLs before passing them through to a wrapped DataSource. Something like:

import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class ResolvingDataSource implements DataSource {

  private static final String RESOLVABLE_SCHEME = "app";

  public static final class Factory implements DataSource.Factory {

    private final DataSource.Factory wrappedFactory;

    public Factory(DataSource.Factory wrappedFactory) {
      this.wrappedFactory = wrappedFactory;
    }

    @Override
    public DataSource createDataSource() {
      return new ResolvingDataSource(wrappedFactory.createDataSource());
    }
  }

  private DataSource wrappedDataSource;

  public ResolvingDataSource(DataSource wrappedDataSource) {
    this.wrappedDataSource = wrappedDataSource;
  }

  @Override
  public void addTransferListener(TransferListener transferListener) {
    wrappedDataSource.addTransferListener(transferListener);
  }

  @Override
  public long open(DataSpec dataSpec) throws IOException {
    if (RESOLVABLE_SCHEME.equals(dataSpec.uri.getScheme())) {
      Uri resolvedUrl = resolveUri(dataSpec.uri);
      dataSpec = new DataSpec(
          resolvedUrl,
          dataSpec.httpMethod,
          dataSpec.httpBody,
          dataSpec.absoluteStreamPosition,
          dataSpec.position,
          dataSpec.length,
          dataSpec.key,
          dataSpec.flags);
    }
    return wrappedDataSource.open(dataSpec);
  }

  @Override
  public int read(byte[] buffer, int offset, int readLength) throws IOException {
    return wrappedDataSource.read(buffer, offset, readLength);
  }

  @Nullable
  @Override
  public Uri getUri() {
    return wrappedDataSource.getUri();
  }

  @Override
  public Map<String, List<String>> getResponseHeaders() {
    return wrappedDataSource.getResponseHeaders();
  }

  @Override
  public void close() throws IOException {
    wrappedDataSource.close();
  }
}

where resolveUri is a method that you'd need to implement. Finally, use an instance of ResolvingDataSource.Factory when creating your MediaSource instances.

@tonihei
Copy link
Collaborator

tonihei commented May 7, 2019

I think the DataSource approach in #5779 (comment) should always be preferred to adding url resolution to the MediaSource as suggested in #5779 (comment). That is because MediaSources can be reused and it's unclear how to handle expiration of resolved uris for example. On the other hand, the DataSources are only created when actually needed and are more flexible as they can be used handle multiple urls (e.g. for different formats in a manifest) instead of the "main" url only.

So this enhancement is really about adding an ExoPlayer-provided implementation of a UriResolvingDataSource. We should also ensure to report onTransferInitializing before the uri resolution takes place.

tonihei added a commit that referenced this issue May 21, 2019
@tonihei
Copy link
Collaborator

tonihei commented May 21, 2019

The commit above adds a DataSource for just-in-time resolution of URIs or DataSpecs to the library.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants