Android Chromecast 搜索行为 - 从头重新启动视频
Android Chromecast Seeking behavior - Restarts Video from begining
我正在尝试在 Google 的 CastCompanionLibrary-android 之上实现自定义搜索 (forward/rewind) 功能。我注意到一个奇怪的行为,尽管用户寻求非零的 seekBar 位置,但演员表上播放的视频被迫从头开始重新启动,完全忽略请求的搜索位置。
我的视频播放器的 SeekBar 侦听器实现
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (mPlaybackState == PlaybackState.PLAYING) {
// determine local or remote playback
switch (mPlaybackLocation) {
case PlaybackLocation.LOCAL:
mLocalVideoView.seekTo(progress);
break;
case PlaybackLocation.REMOTE:
try {
mVideoCastManager.play(progress);
} catch (Exception e) {
CastUtils.handleException(mParentActivity, e);
}
break;
default:
Log.d(TAG, "unknown playback location");
break;
}
} else if (mPlaybackState != PlaybackState.IDLE) {
mLocalVideoView.seekTo(progress);
}
}
与其他 related question 不同,我相信我们的流媒体服务器可以正常工作,因为当我使用默认的 VideoCastControllerActivity class 时,我们会注意到正确的搜索行为。但我们的目标不是使用默认 class,因为它是全屏 activity,并且不能很好地与我们的应用程序配合使用。基本上,我们想要与 Youtube 应用程序完全相同的功能,其中普通搜索栏可以同时控制本地和远程播放器,而无需将当前屏幕切换为全屏。
问题是我的实现与下面发布的参考示例非常相似,即使不完全相同。关键是两者都调用:
mVideoCastManager.play(progress)
;
(并且调用 VideoCastManager.seekAndPlay(int position)都没有成功。事实上,VideoCastControllerActivity 实际上调用了 play(),后者又调用了 seekAndPlay())
参考播放器(Cast-Videos)求implementation
private void play(int position) {
startControllersTimer();
switch (mLocation) {
case LOCAL:
mVideoView.seekTo(position);
mVideoView.start();
break;
case REMOTE:
mPlaybackState = PlaybackState.BUFFERING;
updatePlayButton(mPlaybackState);
try {
mCastManager.play(position);
} catch (Exception e) {
Utils.handleException(this, e);
}
break;
default:
break;
}
restartTrickplayTimer();
}
顺便说一下,我注意到远程播放器上的搜索栏会暂时出现,它甚至没有填满所搜索的正确位置,而是只填满了整个播放器的大约 10%酒吧。请参阅所附图片,其中我从 1:29 视频 (~80%)
中寻找了大约 1:10
这是 CCL 的错误还是我做错了什么?
编辑:搜索期间的接收方和发送方日志
[565.374s] [cast.receiver.IpcChannel] Received message: {"data":"{\"requestId\":7,\"type\":\"SEEK\",\"mediaSessionId\":2,\"currentTime\":0.087,\"resumeState\":\"PLAYBACK_START\"}","namespace":"urn:x-cast:com.google.cast.media","senderId":"14:net.ajplus.beta-19"}
cast_receiver.js:40 [565.382s] [cast.receiver.CastMessageBus] Dispatching CastMessageBus message
cast_receiver.js:40 [565.397s] [cast.receiver.MediaManager] MediaManager message received
cast_receiver.js:40 [565.404s] [cast.receiver.MediaManager] Dispatching MediaManager seek event
cast_receiver.js:40 [565.409s] [cast.receiver.MediaManager] onSeek: {"requestId":7,"mediaSessionId":2,"currentTime":0.087,"resumeState":"PLAYBACK_START"}
cast_receiver.js:40 [565.420s] [cast.receiver.MediaManager] Sending broadcast status message
cast_receiver.js:40 [565.426s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:com.google.cast.media","senderId":"*:*","data":"{\"type\":\"MEDIA_STATUS\",\"status\":[{\"mediaSessionId\":2,\"playbackRate\":1,\"playerState\":\"BUFFERING\",\"currentTime\":0.087,\"supportedMediaCommands\":15,\"volume\":{\"level\":1,\"muted\":false},\"activeTrackIds\":[],\"currentItemId\":2,\"repeatMode\":\"REPEAT_OFF\"}],\"requestId\":7}"}
player.html:1 Mixed Content: The page at 'https://www.gstatic.com/eureka/player/player.html?skin' was loaded over HTTPS, but requested an insecure video 'http://bc29.domain.me/fms/2848955552001/201512/video.mp4'. This content should also be served over HTTPS.
cast_receiver.js:40 [568.490s] [cast.receiver.MediaManager] Buffering state changed, isPlayerBuffering: false old time: 0.12 current time: 1.167672
cast_receiver.js:40 [568.515s] [cast.receiver.MediaManager] Sending broadcast status message
cast_receiver.js:40 [568.538s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:com.google.cast.media","senderId":"*:*","data":"{\"type\":\"MEDIA_STATUS\",\"status\":[{\"mediaSessionId\":2,\"playbackRate\":1,\"playerState\":\"PLAYING\",\"currentTime\":1.229581,\"supportedMediaCommands\":15,\"volume\":{\"level\":1,\"muted\":false},\"activeTrackIds\":[],\"currentItemId\":2,\"repeatMode\":\"REPEAT_OFF\"}],\"requestId\":0}"}
发件人
12-17 15:19:55.803 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] attempting to play media at position 87 seconds
12-17 15:19:55.803 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] attempting to seek media
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] RemoteMediaPlayer::onStatusUpdated() is reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onQueueUpdated() reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] Queue Items size: 1, Item: com.google.android.gms.cast.MediaQueueItem@f2d65998, Repeat Mode: 0, Shuffle: false
12-17 15:19:55.902 5639-5639/net.domain.android D/QueueDataProvider: Queue is updated with a list of size: 1
12-17 15:19:55.902 5639-5639/net.domain.android D/QueueDataProvider: Queue was updated
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] [queue] Queue Item is: {"media":{"contentId":"http://bc29.domain.me/fms/2848955552001/201512/video.mp4","streamType":"BUFFERED","contentType":"video\/mp4","metadata":{"metadataType":1,"images":[{"url":"http:\/\/bc29.ajmn.me\/pd\/2848955552001\/201512\/1316\/2848955552001_4663173896001_RT-60-GOPCNN-TECHNOLOGYSECURITY-151215-FINAL-SUB-thumbnail.jpg?pubId=2848955552001","width":0,"height":0},{"url":"http:\/\/api.domain.net\/pictures\/video_image\/video_Still004.jpg","width":0,"height":0}],"title":"When the GOP geeks out on surveillance technologies","subtitle":"During the fifth GOP debate, candidates went on and on how technologies could prevent the next “terrorist attack.”\r\n"},"duration":89.931},"itemId":2,"autoplay":true,"startTime":0,"preloadTime":20}
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated(): Player status = buffering
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] updateMiniControllersVisibility() reached with visibility: true
12-17 15:19:55.905 5639-5639/net.domain.android D/AJPBaseActivity: onRemoteMediaPlayerStatusUpdated()
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached with status: 4
12-17 15:19:59.123 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] RemoteMediaPlayer::onStatusUpdated() is reached
12-17 15:19:59.123 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onQueueUpdated() reached
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] Queue Items size: 1, Item: com.google.android.gms.cast.MediaQueueItem@f2d65998, Repeat Mode: 0, Shuffle: false
12-17 15:19:59.124 5639-5639/net.domain.android D/QueueDataProvider: Queue is updated with a list of size: 1
12-17 15:19:59.124 5639-5639/net.domain.android D/QueueDataProvider: Queue was updated
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] [queue] Queue Item is: {"media":{"contentId":"http://bc29.domain.me/fms/2848955552001/201512/video.mp4","streamType":"BUFFERED","contentType":"video\/mp4","metadata":{"metadataType":1,"images":[{"url":"http://bc29.domain.me/fms/2848955552001/201512/video_thumbnail.jpg?pubId=2848955552001","width":0,"height":0},{"url":"http://bc29.domain.me/fms/2848955552001/201512/video_Still004.jpg","width":0,"height":0}],"title":"When the GOP geeks out on surveillance technologies","subtitle":"During the fifth GOP debate, candidates went on and on how technologies could prevent the next “terrorist attack.”\r\n"},"duration":89.931},"itemId":2,"autoplay":true,"startTime":0,"preloadTime":20}
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated(): Player status = playing
12-17 15:19:59.125 5639-5639/net.domain.android D/ccl_BaseCastManager: [v2.5.1] startReconnectionService() for media length lef = 88700
12-17 15:19:59.127 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] startNotificationService()
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] updateMiniControllersVisibility() reached with visibility: true
12-17 15:19:59.129 5639-5639/net.domain.android D/AJPBaseActivity: onRemoteMediaPlayerStatusUpdated()
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached with status: 2
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_ReconnectionService: [v2.5.1] onStartCommand() is called
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_ReconnectionService: [v2.5.1] setUpEndTimer(): setting up a timer for the end of current media
12-17 15:19:59.139 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onStartCommand
12-17 15:19:59.139 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onStartCommand(): Action: ACTION_VISIBILITY false
您传递给 "play(position)" 的时间应该以毫秒为单位,但根据您的日志,您以秒为单位传递,因此如果您想要寻找 87 秒,则需要将 87000 传递给该方法(请参阅该方法的 javadoc)。 CCL 中的日志语句应该更正以反映这一点(将在下次更新中修复)但 JavaDoc 是正确的。
我正在尝试在 Google 的 CastCompanionLibrary-android 之上实现自定义搜索 (forward/rewind) 功能。我注意到一个奇怪的行为,尽管用户寻求非零的 seekBar 位置,但演员表上播放的视频被迫从头开始重新启动,完全忽略请求的搜索位置。
我的视频播放器的 SeekBar 侦听器实现
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (mPlaybackState == PlaybackState.PLAYING) {
// determine local or remote playback
switch (mPlaybackLocation) {
case PlaybackLocation.LOCAL:
mLocalVideoView.seekTo(progress);
break;
case PlaybackLocation.REMOTE:
try {
mVideoCastManager.play(progress);
} catch (Exception e) {
CastUtils.handleException(mParentActivity, e);
}
break;
default:
Log.d(TAG, "unknown playback location");
break;
}
} else if (mPlaybackState != PlaybackState.IDLE) {
mLocalVideoView.seekTo(progress);
}
}
与其他 related question 不同,我相信我们的流媒体服务器可以正常工作,因为当我使用默认的 VideoCastControllerActivity class 时,我们会注意到正确的搜索行为。但我们的目标不是使用默认 class,因为它是全屏 activity,并且不能很好地与我们的应用程序配合使用。基本上,我们想要与 Youtube 应用程序完全相同的功能,其中普通搜索栏可以同时控制本地和远程播放器,而无需将当前屏幕切换为全屏。
问题是我的实现与下面发布的参考示例非常相似,即使不完全相同。关键是两者都调用:
mVideoCastManager.play(progress)
;
(并且调用 VideoCastManager.seekAndPlay(int position)都没有成功。事实上,VideoCastControllerActivity 实际上调用了 play(),后者又调用了 seekAndPlay())
参考播放器(Cast-Videos)求implementation
private void play(int position) {
startControllersTimer();
switch (mLocation) {
case LOCAL:
mVideoView.seekTo(position);
mVideoView.start();
break;
case REMOTE:
mPlaybackState = PlaybackState.BUFFERING;
updatePlayButton(mPlaybackState);
try {
mCastManager.play(position);
} catch (Exception e) {
Utils.handleException(this, e);
}
break;
default:
break;
}
restartTrickplayTimer();
}
顺便说一下,我注意到远程播放器上的搜索栏会暂时出现,它甚至没有填满所搜索的正确位置,而是只填满了整个播放器的大约 10%酒吧。请参阅所附图片,其中我从 1:29 视频 (~80%)
中寻找了大约 1:10这是 CCL 的错误还是我做错了什么?
编辑:搜索期间的接收方和发送方日志
[565.374s] [cast.receiver.IpcChannel] Received message: {"data":"{\"requestId\":7,\"type\":\"SEEK\",\"mediaSessionId\":2,\"currentTime\":0.087,\"resumeState\":\"PLAYBACK_START\"}","namespace":"urn:x-cast:com.google.cast.media","senderId":"14:net.ajplus.beta-19"}
cast_receiver.js:40 [565.382s] [cast.receiver.CastMessageBus] Dispatching CastMessageBus message
cast_receiver.js:40 [565.397s] [cast.receiver.MediaManager] MediaManager message received
cast_receiver.js:40 [565.404s] [cast.receiver.MediaManager] Dispatching MediaManager seek event
cast_receiver.js:40 [565.409s] [cast.receiver.MediaManager] onSeek: {"requestId":7,"mediaSessionId":2,"currentTime":0.087,"resumeState":"PLAYBACK_START"}
cast_receiver.js:40 [565.420s] [cast.receiver.MediaManager] Sending broadcast status message
cast_receiver.js:40 [565.426s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:com.google.cast.media","senderId":"*:*","data":"{\"type\":\"MEDIA_STATUS\",\"status\":[{\"mediaSessionId\":2,\"playbackRate\":1,\"playerState\":\"BUFFERING\",\"currentTime\":0.087,\"supportedMediaCommands\":15,\"volume\":{\"level\":1,\"muted\":false},\"activeTrackIds\":[],\"currentItemId\":2,\"repeatMode\":\"REPEAT_OFF\"}],\"requestId\":7}"}
player.html:1 Mixed Content: The page at 'https://www.gstatic.com/eureka/player/player.html?skin' was loaded over HTTPS, but requested an insecure video 'http://bc29.domain.me/fms/2848955552001/201512/video.mp4'. This content should also be served over HTTPS.
cast_receiver.js:40 [568.490s] [cast.receiver.MediaManager] Buffering state changed, isPlayerBuffering: false old time: 0.12 current time: 1.167672
cast_receiver.js:40 [568.515s] [cast.receiver.MediaManager] Sending broadcast status message
cast_receiver.js:40 [568.538s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:com.google.cast.media","senderId":"*:*","data":"{\"type\":\"MEDIA_STATUS\",\"status\":[{\"mediaSessionId\":2,\"playbackRate\":1,\"playerState\":\"PLAYING\",\"currentTime\":1.229581,\"supportedMediaCommands\":15,\"volume\":{\"level\":1,\"muted\":false},\"activeTrackIds\":[],\"currentItemId\":2,\"repeatMode\":\"REPEAT_OFF\"}],\"requestId\":0}"}
发件人
12-17 15:19:55.803 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] attempting to play media at position 87 seconds
12-17 15:19:55.803 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] attempting to seek media
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] RemoteMediaPlayer::onStatusUpdated() is reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onQueueUpdated() reached
12-17 15:19:55.902 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] Queue Items size: 1, Item: com.google.android.gms.cast.MediaQueueItem@f2d65998, Repeat Mode: 0, Shuffle: false
12-17 15:19:55.902 5639-5639/net.domain.android D/QueueDataProvider: Queue is updated with a list of size: 1
12-17 15:19:55.902 5639-5639/net.domain.android D/QueueDataProvider: Queue was updated
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] [queue] Queue Item is: {"media":{"contentId":"http://bc29.domain.me/fms/2848955552001/201512/video.mp4","streamType":"BUFFERED","contentType":"video\/mp4","metadata":{"metadataType":1,"images":[{"url":"http:\/\/bc29.ajmn.me\/pd\/2848955552001\/201512\/1316\/2848955552001_4663173896001_RT-60-GOPCNN-TECHNOLOGYSECURITY-151215-FINAL-SUB-thumbnail.jpg?pubId=2848955552001","width":0,"height":0},{"url":"http:\/\/api.domain.net\/pictures\/video_image\/video_Still004.jpg","width":0,"height":0}],"title":"When the GOP geeks out on surveillance technologies","subtitle":"During the fifth GOP debate, candidates went on and on how technologies could prevent the next “terrorist attack.”\r\n"},"duration":89.931},"itemId":2,"autoplay":true,"startTime":0,"preloadTime":20}
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated(): Player status = buffering
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] updateMiniControllersVisibility() reached with visibility: true
12-17 15:19:55.905 5639-5639/net.domain.android D/AJPBaseActivity: onRemoteMediaPlayerStatusUpdated()
12-17 15:19:55.905 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached with status: 4
12-17 15:19:59.123 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] RemoteMediaPlayer::onStatusUpdated() is reached
12-17 15:19:59.123 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onQueueUpdated() reached
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] Queue Items size: 1, Item: com.google.android.gms.cast.MediaQueueItem@f2d65998, Repeat Mode: 0, Shuffle: false
12-17 15:19:59.124 5639-5639/net.domain.android D/QueueDataProvider: Queue is updated with a list of size: 1
12-17 15:19:59.124 5639-5639/net.domain.android D/QueueDataProvider: Queue was updated
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] [queue] Queue Item is: {"media":{"contentId":"http://bc29.domain.me/fms/2848955552001/201512/video.mp4","streamType":"BUFFERED","contentType":"video\/mp4","metadata":{"metadataType":1,"images":[{"url":"http://bc29.domain.me/fms/2848955552001/201512/video_thumbnail.jpg?pubId=2848955552001","width":0,"height":0},{"url":"http://bc29.domain.me/fms/2848955552001/201512/video_Still004.jpg","width":0,"height":0}],"title":"When the GOP geeks out on surveillance technologies","subtitle":"During the fifth GOP debate, candidates went on and on how technologies could prevent the next “terrorist attack.”\r\n"},"duration":89.931},"itemId":2,"autoplay":true,"startTime":0,"preloadTime":20}
12-17 15:19:59.124 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] onRemoteMediaPlayerStatusUpdated(): Player status = playing
12-17 15:19:59.125 5639-5639/net.domain.android D/ccl_BaseCastManager: [v2.5.1] startReconnectionService() for media length lef = 88700
12-17 15:19:59.127 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] startNotificationService()
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_VideoCastManager: [v2.5.1] updateMiniControllersVisibility() reached with visibility: true
12-17 15:19:59.129 5639-5639/net.domain.android D/AJPBaseActivity: onRemoteMediaPlayerStatusUpdated()
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onRemoteMediaPlayerStatusUpdated() reached with status: 2
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_ReconnectionService: [v2.5.1] onStartCommand() is called
12-17 15:19:59.129 5639-5639/net.domain.android D/ccl_ReconnectionService: [v2.5.1] setUpEndTimer(): setting up a timer for the end of current media
12-17 15:19:59.139 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onStartCommand
12-17 15:19:59.139 5639-5639/net.domain.android D/ccl_VideoCastNotificat: [v2.5.1] onStartCommand(): Action: ACTION_VISIBILITY false
您传递给 "play(position)" 的时间应该以毫秒为单位,但根据您的日志,您以秒为单位传递,因此如果您想要寻找 87 秒,则需要将 87000 传递给该方法(请参阅该方法的 javadoc)。 CCL 中的日志语句应该更正以反映这一点(将在下次更新中修复)但 JavaDoc 是正确的。