【问题标题】:How to add a custom SessionProvider with Google Cast SDK 3如何使用 Google Cast SDK 3 添加自定义 SessionProvider
【发布时间】:2017-01-02 02:31:12
【问题描述】:

我们最近将 Google Cast SDK 更新到了版本 3。有了这个 SDK,应该可以通过在 OptionsProvider 中实现 getAdditionalSessionProviders() 来添加对非投射设备的支持。我们创建了一个自定义 SessionProvider 以使用 getAdditionalSessionProviders() 方法返回。

然而,这个 SessionProvider 永远不会被使用,并且它可能只会在一个设备被发现并在选择列表中被选中时使用,当按下MediaRouteButton 时,如Session 文档中所述。但是我们找不到将我们发现的非广播设备添加到此列表的方法。我们搜索了在线可用的 API、文档和示例,但找不到如何执行此操作。我们只找到了旧 sdk 版本的示例,但它们完全不同且不可用。

我们希望使用此功能通过三星的 SmartView SDK 将三星电视添加到 Google Cast 列表中,就像 YouTube 和 Netflix 应用一样。

【问题讨论】:

  • 你试过执行Cast SDK v3 Android Codelab吗?另外,请检查此document
  • 是的,我已经检查过了,但我找不到任何关于在那里添加非投射设备的信息。不过,我们已经成功实现了 SDK 的所有其他部分。
  • 看看这个(productforums.google.com/forum/#!topic/chromecast/hoHJMeM5Qns)如果它可以帮助你交配。
  • @AndroidEnthusiast 对此线程的两个完全无响应的回复。这两个来源都没有远程解决所提出的问题。你在浪费人们的时间。请不要那样做。

标签: android chromecast google-cast samsung-smart-tv


【解决方案1】:

创建自定义媒体路由提供程序:这是一个用于自定义媒体路由的假 MediaRouteProvider。这个类除了发布一个假的自定义 MediaRoute 之外什么都不做,这样它就可以被来自 MediaRouter 的 Cast SDK 看到和选择。

import android.content.Context;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v7.media.MediaRouteDescriptor;
import android.support.v7.media.MediaRouteDiscoveryRequest;
import android.support.v7.media.MediaRouteProvider;
import android.support.v7.media.MediaRouteProvider.RouteController;
import android.support.v7.media.MediaRouteProviderDescriptor;
import android.support.v7.media.MediaRouter;
import java.util.ArrayList;

public final class CustomMediaRouteProvider extends MediaRouteProvider {
  private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
  private static MediaRouteDescriptor DEFAULT_MEDIA_ROUTE_DESCRIPTOR;

  static {
    // This filter will be used by Cast SDK to match the session category.
    IntentFilter customControls = new IntentFilter();
    customControls.addCategory(CustomSessionProvider.CUSTOM_CATEGORY);

    CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
    CONTROL_FILTERS_BASIC.add(customControls);

    Bundle extras = new Bundle();
    extras.putCharSequence("ROUTE_URL", "http://abcdef.cyz");
    DEFAULT_MEDIA_ROUTE_DESCRIPTOR =
        new MediaRouteDescriptor.Builder("fake-custom-route-id", "fake custom route")
            .setDescription("Foo description")
            .addControlFilters(CONTROL_FILTERS_BASIC)
            .setPlaybackStream(AudioManager.STREAM_MUSIC)
            .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
            .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
            .setVolumeMax(100)
            .setVolume(10)
            .setExtras(extras)
            .build();
  }

  public CustomMediaRouteProvider(Context context) {
    super(context);
  }

  @Override
  public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
    if (request == null || request.getSelector() == null) {
      return;
    }

    publishRoutes();
  }

  @Override
  public RouteController onCreateRouteController(String routeId) {
    return null;
  }

  private void publishRoutes() {
    MediaRouteProviderDescriptor providerDescriptor =
        new MediaRouteProviderDescriptor.Builder().addRoute(DEFAULT_MEDIA_ROUTE_DESCRIPTOR).build();

    setDescriptor(providerDescriptor);
  }
}

您的自定义会话需要一个 SessionProvider 实现:

import android.content.Context;
import com.google.android.gms.cast.framework.Session;
import com.google.android.gms.cast.framework.SessionProvider;

public class CustomSessionProvider extends SessionProvider {
  public static final String CUSTOM_CATEGORY = "CUSTOM";

  public CustomSessionProvider(Context applicationContext) {
    super(applicationContext, CUSTOM_CATEGORY);
  }

  @Override
  public Session createSession(String sessionId) {
    return new CustomSession(getContext(), getCategory(), sessionId);
  }

  @Override
  public boolean isSessionRecoverable() {
    return true;
  }
}

还有一个 Session 实现:这是一个自定义媒体路由类型的假 Session 实现。它总是在开始/恢复/结束时成功。

import android.content.Context;
import android.os.Bundle;
import com.google.android.gms.cast.framework.Session;

public class CustomSession extends Session {
  private static final String FAKE_SESSION_ID = "custom.session.id.12345";

  CustomSession(Context applicationContext, String category, String sessionId) {
    super(applicationContext, category, sessionId);
  }

  @Override
  protected void start(Bundle routeInfoExtra) {
    notifySessionStarted(FAKE_SESSION_ID);
  }

  @Override
  protected void resume(Bundle routeInfoExtra) {
    notifySessionResumed(false);
  }

  @Override
  protected void end(boolean stopCasting) {
    notifySessionEnded(0);
  }
}

在您的 Cast V3 发送者应用中,指定额外的会话提供者:

public class CastOptionsProvider implements OptionsProvider {
@Override
  public List<SessionProvider> getAdditionalSessionProviders(Context appContext) {
    List<SessionProvider> additionalProviders = new ArrayList<>();
    additionalProviders.add(new CustomSessionProvider(appContext));
    return additionalProviders;
  }
}

在您的应用程序中添加 MediaRouter 提供程序:

public class CastVideosApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    MediaRouter mediaRouter = MediaRouter.getInstance(this);
    mediaRouter.addProvider(new CustomMediaRouteProvider(this));
  }
}

【讨论】:

  • 太好了,我仍然不清楚如何使用 CastSession 和 CustomSession(同时使用两者)以及自定义会话如何与 CustomMediaRouteProvider 交互,我们是否必须使用 RemotePlaybackClient
  • 在您启用投射的应用中,所有自定义路线都将作为投射会话被发现和管理。
  • 我正在 uamp 中测试我的自定义路由,现在我在 MusicService CastSessionManagerListener 中检查会话实例并创建适当的播放(CastPlayback/CustomPlayback),这按预期工作,这是正确的方法还是我是走错方向?这是要点gist.github.com/ingsaurabh/6b47babd0d1e64cf144b4d5117bf0c9c
  • 你能解释一下 FAKE_SESSION_ID 是什么吗?与在构造函数中传入的 getSessionID() 相反(在我的代码中为 null 效果不太好)。
  • @LeonNicholls 您能否扩展一下“作为演员会议发现和管理的内容”。据我所知,这似乎意味着“投射会话和您的会话不能同时运行”,同时除了从投射按钮中选择设备之外,绝对不提供任何支持或集成到 UI 中。不支持在框架动作和 MediaRouter 意图之间进行转换(清楚地映射,但未处理);没有集成控制元素。那准确吗?我通过投射按钮进行设备选择。从那里我看不到前进的道路。
【解决方案2】:

所以,我遇到了和你一样的问题,我找到了一些让它工作的方法,但正如你所说,由于没有关于这个主题的真正记录,我不确定这是“正确的做法它”。

这基本上是我的工作:

媒体路由提供者负责管理您的设备和所有相关的命令/通信。您可以使用Media Router API 使用非常简单的应用程序对其进行测试。 googlesample 中有一个关于媒体路由器的 github:Android BasicMediaRouter Sample

在您的自定义 Session 类中,您可以访问 MediaRouter(您在构造函数中传递了上下文)并检索当前的Route

 MediaRouter mediaRouter = MediaRouter.getInstance(context);
  if (mediaRouter != null && mediaRouter.getSelectedRoute() != null)
    Log.d("Cast", "Selected route name is " +  mediaRouter.getSelectedRoute().getName());

这样,您应该能够获取当前选择的设备(您将在 Session 的 start() 方法中收到通知),并将命令从 Session 对象传递给您的媒体路由提供程序,如媒体路由示例中所做的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2019-10-08
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多