- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个实现 MediaBrowserServiceCompat()
的 PlaybackService.kt
类,因为它是 Android Auto 支持所必需的。播放器本身在应用程序内运行良好。该应用 95% 用于几个不同 channel 之间的 HLS 流(5% 是音频样本文件)。
我可以成功获取我的 Root View ,它是一个简单的 channel 列表(“直播”、“80 年代”、“90 年代”等),当我单击其中一个时,音频开始播放,但我卡在了“正在获取您的选择...”屏幕,如下所示。查看logcat,没有报错。有一点可能很奇怪,也可能很正常,onGetRoot
在选择 channel 后再次调用。
这是我的整个 PlaybackService.kt
文件。
package <my-package>.audio.service
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.os.ResultReceiver
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.util.Log
import androidx.annotation.MainThread
import androidx.core.content.ContextCompat
import androidx.media.MediaBrowserServiceCompat
import androidx.media.session.MediaButtonReceiver
import <my-package>.MainActivity
import <my-package>.R
import <my-package>.audio.api.ChannelApi
import <my-package>.audio.api.StreamApi
import <my-package>.audio.models.NetworkChannel
import <my-package>.audio.models.State
import <my-package>.audio.utils.StorageHelper
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame
import com.google.android.exoplayer2.metadata.id3.UrlLinkFrame
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.util.MimeTypes
import com.npaw.youbora.lib6.exoplayer2.Exoplayer2Adapter
import com.npaw.youbora.lib6.plugin.Options
import com.npaw.youbora.lib6.plugin.Plugin
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.util.*
open class PlaybackService : MediaBrowserServiceCompat() {
var reactContext: ReactContext? = null
private val binder = PlaybackBinder()
private val scope = MainScope()
private var sourceUrl: String? = null
private var isForegroundService = false
private val playerListener = playerListener()
private val playbackAudioAttributes = AudioAttributes.Builder()
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA)
.build()
private val player: ExoPlayer by lazy {
ExoPlayer.Builder(this).build().apply {
setAudioAttributes(playbackAudioAttributes, true)
setHandleAudioBecomingNoisy(true)
setWakeMode(C.WAKE_MODE_NETWORK)
addListener(playerListener)
setPlaybackSpeed(1.0f)
playWhenReady = true
}
}
private val youboraOptions = Options()
private lateinit var youboraPlugin: Plugin
private lateinit var notificationManager: NotificationManager
private lateinit var mediaSession: MediaSessionCompat
private lateinit var mediaSessionConnector: MediaSessionConnector
private var autoStations: List<NetworkChannel>? = null
private lateinit var appName: String
// START: Audio Module actions
fun play(streamName: String){
Log.d(TAG, "Processing stream: $streamName")
youboraOptions.contentChannel = streamName
buildStreamAndPlay(streamName)
}
fun playHook(hookUri: String, songTitle: String, artistName: String){
Log.d(TAG, "Process hook file: $hookUri")
youboraOptions.contentTitle = "$songTitle-$artistName"
buildMediaAndPlay(hookUri)
}
fun stop(){
Log.d(TAG, "Stopping stream.")
player.stop()
player.clearMediaItems()
}
fun getPlaybackState(): Int {
return player.playbackState
}
// END: Audio Module actions
override fun onCreate() {
Log.d(TAG, "onCreate")
super.onCreate()
appName = applicationContext.getString(R.string.app_name)
val sessionActivityPendingIntent = PendingIntent.getActivity(
/* context = */ reactContext ?: applicationContext,
/* requestCode = */ 0,
/* intent = */ Intent(reactContext ?: applicationContext, MainActivity::class.java),
/* flags = */ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
mediaSession = MediaSessionCompat(this, TAG).apply {
setSessionActivity(sessionActivityPendingIntent)
isActive = true
}
sessionToken = mediaSession.sessionToken
notificationManager = NotificationManager(
this,
mediaSession.sessionToken,
PlayerNotificationListener()
)
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector.setPlaybackPreparer(AudioServicePreparer())
mediaSessionConnector.setPlayer(player)
notificationManager.showNotificationForPlayer(player)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand")
MediaButtonReceiver.handleIntent(mediaSession, intent)
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder {
if (intent != null) {
if(SERVICE_INTERFACE == intent.action){
return super.onBind(intent)!!
}
}
return binder
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
player.stop()
player.clearMediaItems()
}
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): BrowserRoot? {
Log.d(TAG, "onGetRoot called")
return BrowserRoot(MEDIA_ROOT_ID, null)
}
override fun onLoadChildren(
parentId: String,
result: Result<List<MediaBrowserCompat.MediaItem>>
) {
Log.d(TAG, "OnLoadChildren: parentMediaId = $parentId")
if(EMPTY_MEDIA_ROOT_ID == parentId){
result.sendResult(null)
return
}
val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()
if(MEDIA_ROOT_ID == parentId){
// Build list of channels
Log.d(TAG, "Building root items")
if (autoStations != null) {
Log.d(TAG, "Channels exist, creating media items...")
for (i in 0 until autoStations!!.size) {
val station = autoStations!![i]
val mediaItem = createMediaItem(station)
if (mediaItem != null) {
mediaItems.add(mediaItem)
}
}
result.sendResult(mediaItems)
} else {
Log.d(TAG, "Making call to get channels...")
result.detach()
scope.launch {
try {
autoStations = ChannelApi.retrofitService.getChannels()
if (autoStations!!.isNotEmpty()) {
Log.d(TAG, "Stations fetched, creating media items...")
for (station in autoStations!!) {
val mediaItem = createMediaItem(station)
if (mediaItem != null) {
mediaItems.add(mediaItem)
}
}
result.sendResult(mediaItems)
}else{
useFallbackStation()
}
} catch (err: Exception) {
Log.e(TAG, "Failed to get channels from API. Reason: ${err.message}")
result.sendResult(mediaItems)
}
}
}
} else{
result.sendResult(mediaItems)
}
}
private fun createMediaItem(station: NetworkChannel): MediaBrowserCompat.MediaItem? {
return try {
val description = MediaDescriptionCompat.Builder()
.setMediaId(station.streamName)
.setTitle(station.title)
val isDarkMode = (reactContext ?: applicationContext).resources.configuration.uiMode == Configuration.UI_MODE_NIGHT_YES
if (isDarkMode) {
description.setIconUri(
Uri.parse("<my-cdn>" + station.streamName + "/album-md.png")
)
} else {
description.setIconUri(
Uri.parse("<my-cdn>" + station.streamName + "/album-md-dark.png")
)
}
MediaBrowserCompat.MediaItem(
description.build(),
MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
)
} catch (ex: Exception) {
null
}
}
private fun useFallbackStation() {
autoStations = List(1) {
NetworkChannel(
channelId = 5,
title = appName,
streamName = appName.lowercase(Locale.getDefault()),
slug = "live",
inactiveOn = null
)
}
}
override fun onDestroy() {
scope.cancel()
mediaSession.run {
isActive = false
release()
}
player.removeListener(playerListener)
player.release()
super.onDestroy()
}
private fun playStream(){
Log.d(TAG, "playStream - sourceUrl: $sourceUrl")
player.clearMediaItems()
val mediaItem = MediaItem.Builder()
.setUri(sourceUrl)
.setMimeType(MimeTypes.APPLICATION_M3U8)
.setLiveConfiguration(
MediaItem.LiveConfiguration.Builder()
.setMaxPlaybackSpeed(1.02f)
.build()
)
.build()
// Testing adding metadata for AA issue, no change...
mediaSession.setMetadata(MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Test 1")
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Test 2")
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, -1)
.build())
if (player.isPlaying || player.isLoading) {
stop()
}
player.addMediaItem(mediaItem)
player.prepare()
}
private fun buildStreamAndPlay(streamName: String) {
scope.launch {
sourceUrl = StreamApi.retrofitService.getStreamUrl(
mapOf(
"encoding" to "hls",
"platform" to "android",
"network" to streamName,
)
).data.streamUrl
Log.d(TAG, "Got stream url: $sourceUrl")
playStream()
}
}
private fun buildMediaAndPlay(hookUri: String) = scope.launch {
val userData = StorageHelper.getUserData(reactContext ?: applicationContext)
if(!::youboraPlugin.isInitialized && reactContext != null){
youboraPlugin = Plugin(youboraOptions, reactContext)
youboraPlugin.activity = reactContext?.currentActivity
Exoplayer2Adapter(player)
.also { adapter ->
youboraPlugin.adapter = adapter
}
}
if (player.isPlaying == true || player.isLoading == true) {
stop()
}
val mediaItem = MediaItem.Builder()
.setUri(hookUri)
.build()
player.addMediaItem(mediaItem)
player.prepare()
player.play()
}
@MainThread
private fun playerListener() = object: Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
val state: State = when (playbackState){
ExoPlayer.STATE_IDLE -> State.Idle
ExoPlayer.STATE_BUFFERING -> State.Buffering
ExoPlayer.STATE_READY -> State.Ready
ExoPlayer.STATE_ENDED -> State.Stopped
else -> State.Stopped
}
if(state != State.Buffering){
notificationManager.hideNotification()
}
Log.d(TAG, "PlayerState: $state")
sendEvent(EVENT_PLAYER_STATE, state.state )
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
if(isPlaying) {
Log.d(TAG, "PlayerState: Playing")
notificationManager.showNotificationForPlayer(player)
sendEvent(EVENT_PLAYER_STATE, State.Playing.state)
}else{
Log.d(TAG, "PlayerState: Paused (Stopping and clearing)")
sendEvent(EVENT_PLAYER_STATE, State.Paused.state)
player.stop()
player.clearMediaItems()
}
}
override fun onPlayerError(error: PlaybackException) {
sendEvent(EVENT_PLAYER_STATE, State.Error.state)
super.onPlayerError(error)
}
override fun onMetadata(metadata: com.google.android.exoplayer2.metadata.Metadata) {
var handled = false
var id: String? = null
var title: String? = null
var artist: String? = null
var isBreak = false
Log.d(TAG, "Raw Meta: $metadata")
(0 until metadata.length()).forEach { i ->
when (val entry = metadata[i]) {
is TextInformationFrame -> {
when (entry.id.uppercase()) {
"TIT2", "TT2" -> {
if(entry.value.isNotEmpty()){ // Added to due current bug with empty metadata
handled = true
title = entry.value
}
}
"TOPE", "TPE1", "TP1" -> {
handled = true
artist = entry.value
}
"TUID" -> {
handled = true
id = entry.value
}
}
}
is UrlLinkFrame -> {
when (entry.id.uppercase()) {
"WXXX" -> {
handled = true
if (id == null) {
id = entry.url
}
}
}
}
}
}
if (handled){
try {
UUID.fromString(id)
} catch (ignored: Exception) {
Log.d(TAG, "Detected stream break.")
id = null
isBreak = true
}
notificationManager.currentArtist = artist.toString()
notificationManager.currentSong = title.toString()
youboraOptions.contentTitle = "$title-$artist"
youboraOptions.contentId = "$id"
youboraOptions.contentBitrate = player.audioFormat?.bitrate?.toLong()
Arguments.createMap().apply {
putString("id", id)
putString("title", title)
putString("artist", artist)
putBoolean("isBreak", isBreak)
sendEvent(EVENT_METADATA, this)
}
}
}
}
private fun sendEvent(eventName: String, params: WritableMap?){
reactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
?.emit(eventName, params)
}
private fun sendEvent(eventName: String, eventValue: String){
reactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
?.emit(eventName, eventValue)
}
inner class PlaybackBinder: Binder(){
val service = this@PlaybackService
}
/**
* Listen for notification events.
*/
private inner class PlayerNotificationListener :
PlayerNotificationManager.NotificationListener {
override fun onNotificationPosted(
notificationId: Int,
notification: Notification,
ongoing: Boolean
) {
if (ongoing && !isForegroundService) {
ContextCompat.startForegroundService(
applicationContext,
Intent(applicationContext, this@PlaybackService.javaClass)
)
startForeground(notificationId, notification)
isForegroundService = true
}
}
override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
stopForeground(true)
isForegroundService = false
stopSelf()
}
}
private inner class AudioServicePreparer: MediaSessionConnector.PlaybackPreparer {
override fun onCommand(
player: Player,
command: String,
extras: Bundle?,
cb: ResultReceiver?
): Boolean = false
override fun getSupportedPrepareActions(): Long =
PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID or
PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID or
PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH or
PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH
override fun onPrepare(playWhenReady: Boolean) {
Log.d(TAG, "[AudioServicePreparer] - onPrepare")
// TODO: Should get last played station
onPrepareFromMediaId("<default-media-id>", playWhenReady, null)
}
override fun onPrepareFromMediaId(
mediaId: String,
playWhenReady: Boolean,
extras: Bundle?
) {
Log.d(TAG, "[AudioServicePreparer] - onPrepareFromMediaId - $mediaId - playWhenReady? $playWhenReady")
player.playWhenReady = playWhenReady
play(mediaId)
}
override fun onPrepareFromSearch(query: String, playWhenReady: Boolean, extras: Bundle?) {
Log.d(TAG, "[AudioServicePreparer] - onPrepareFromSearch")
// TODO: Should search for station
play("<default-media-id>")
}
override fun onPrepareFromUri(uri: Uri, playWhenReady: Boolean, extras: Bundle?) = Unit
}
companion object {
const val TAG = "PlaybackService"
const val EVENT_PLAYER_STATE = "onPlayerStateChanged"
const val EVENT_METADATA = "onMetadataReceived"
private const val MEDIA_ROOT_ID = "my_root"
private const val EMPTY_MEDIA_ROOT_ID = "my_empty_root"
}
}
在 Android Auto 中选择站点时的 Logcat 输出:
2022-11-22 17:11:08.293 2264-2264 PlaybackService <my-package> D [AudioServicePreparer] - onPrepareFromMediaId - <stream-name> - playWhenReady? true
2022-11-22 17:11:08.304 2264-2264 PlaybackService <my-package> D Processing stream: <stream-name>
2022-11-22 17:11:08.305 2264-2264 PlaybackService <my-package> D playStream - sourceUrl: <valid-url>
2022-11-22 17:11:08.395 2264-2264 PlaybackService <my-package> D PlayerState: Buffering
2022-11-22 17:11:08.397 2264-2476 ReactNativeJS <my-package> I 'STATE:', 'buffering'
2022-11-22 17:11:11.102 2264-2521 DMCodecAdapterFactory <my-package> I Creating an asynchronous MediaCodec adapter for track type audio
2022-11-22 17:11:11.105 2264-9864 CCodec <my-package> I state->set(ALLOCATING)
2022-11-22 17:11:11.105 2264-9864 CCodec <my-package> I allocate(c2.android.aac.decoder)
2022-11-22 17:11:11.111 2264-9864 CCodec <my-package> I setting up 'default' as default (vendor) store
2022-11-22 17:11:11.114 2264-9864 CCodec <my-package> I Created component [c2.android.aac.decoder]
2022-11-22 17:11:11.114 2264-9864 CCodec <my-package> I state->set(ALLOCATED)
2022-11-22 17:11:11.115 2264-9864 CCodecConfig <my-package> D read media type: audio/mp4a-latm
2022-11-22 17:11:11.123 2264-9864 CCodecConfig <my-package> I query failed after returning 19 values (BAD_INDEX)
2022-11-22 17:11:11.124 2264-9864 MediaCodec <my-package> I MediaCodec will operate in async mode
2022-11-22 17:11:11.125 2264-9864 CCodec <my-package> D [c2.android.aac.decoder] buffers are bound to CCodec for this session
2022-11-22 17:11:11.125 2264-9864 CCodec <my-package> I appPid(2264) width(0) height(0)
2022-11-22 17:11:11.125 2264-9864 CCodecConfig <my-package> D no c2 equivalents for log-session-id
2022-11-22 17:11:11.125 2264-9864 CCodecConfig <my-package> D no c2 equivalents for flags
2022-11-22 17:11:11.126 2264-9864 CCodecConfig <my-package> D c2 config diff is c2::u32 raw.channel-count.value = 2
2022-11-22 17:11:11.126 2264-9864 Codec2Client <my-package> W query -- param skipped: index = 1107298332.
2022-11-22 17:11:11.126 2264-9864 CCodecConfig <my-package> I query failed after returning 19 values (BAD_INDEX)
2022-11-22 17:11:11.127 2264-2521 MediaCodec <my-package> D keep callback message for reclaim
2022-11-22 17:11:11.128 2264-9864 CCodec <my-package> I state->set(STARTING)
2022-11-22 17:11:11.132 2264-9864 Codec2Client <my-package> W query -- param skipped: index = 1342179345.
2022-11-22 17:11:11.132 2264-9864 Codec2Client <my-package> W query -- param skipped: index = 2415921170.
2022-11-22 17:11:11.132 2264-9864 Codec2Client <my-package> W query -- param skipped: index = 1610614798.
2022-11-22 17:11:11.135 2264-9864 CCodec <my-package> I state->set(RUNNING)
2022-11-22 17:11:11.135 2264-9864 CCodecBufferChannel <my-package> I [c2.android.aac.decoder#96] 4 initial input buffers available
2022-11-22 17:11:11.136 2264-2980 BufferPoolAccessor2.0 <my-package> D bufferpool2 0xb40000701ca21d68 : 0(0 size) total buffers - 0(0 size) used buffers - 3845/3850 (recycle/alloc) - 5/3845 (fetch/transfer)
2022-11-22 17:11:11.136 2264-2980 BufferPoolAccessor2.0 <my-package> D Destruction - bufferpool2 0xb40000701ca21d68 cached: 0/0M, 0/0% in use; allocs: 3850, 100% recycled; transfers: 3845, 100% unfetched
2022-11-22 17:11:11.140 2264-2264 PlaybackService <my-package> D PlayerState: Ready
2022-11-22 17:11:11.141 2264-2476 ReactNativeJS <my-package> I 'STATE:', 'ready'
2022-11-22 17:11:11.147 2264-2264 PlaybackService <my-package> D PlayerState: Playing
2022-11-22 17:11:11.148 2264-2264 PlaybackService <my-package> D Raw Meta: entries=[PRIV: owner=com.apple.streaming.transportStreamTimestamp]
2022-11-22 17:11:11.149 2264-2264 PlaybackService <my-package> D Raw Meta: entries=[TIT2: description=null: value=]
2022-11-22 17:11:11.154 2264-9864 CCodecConfig <my-package> D c2 config diff is c2::u32 raw.channel-mask.value = 12
2022-11-22 17:11:11.163 2264-2264 PlaybackService <my-package> D onStartCommand
2022-11-22 17:11:11.172 2264-2521 AudioTrack <my-package> D setVolume(1.000000, 1.000000) pid : 2264
2022-11-22 17:11:11.238 2264-2521 AudioTrack <my-package> D getTimestamp_l(74): device stall time corrected using current time 2384346281016
2022-11-22 17:11:11.274 2264-2476 ReactNativeJS <my-package> I 'STATE:', 'playing'
2022-11-22 17:11:11.372 2264-2476 ReactNativeJS <my-package> I Metadata is undefined
2022-11-22 17:11:12.523 2264-2476 ReactNativeJS <my-package> I Token is not expired
2022-11-22 17:11:12.651 2264-2478 RNFBCrashlyticsInit <my-package> D isCrashlyticsCollectionEnabled via RNFBJSON: true
2022-11-22 17:11:12.652 2264-2478 RNFBCrashlyticsInit <my-package> D isCrashlyticsCollectionEnabled after checking crashlytics_debug_enabled: false
2022-11-22 17:11:12.652 2264-2478 RNFBCrashlyticsInit <my-package> D isCrashlyticsCollectionEnabled final value: false
2022-11-22 17:11:14.406 2264-2977 CCodecBufferChannel <my-package> D [c2.android.aac.decoder#96] DEBUG: elapsed: n=6 [in=0 pipeline=0 out=2]
2022-11-22 17:11:16.930 2264-2264 ViewRootIm...nActivity] <my-package> I ViewPostIme pointer 0
2022-11-22 17:11:17.069 2264-2264 ViewRootIm...nActivity] <my-package> I ViewPostIme pointer 1
2022-11-22 17:11:17.082 2264-2264 PlaybackService <my-package> D Stopping stream.
2022-11-22 17:11:17.086 2264-9864 CCodec <my-package> I state->set(FLUSHING)
2022-11-22 17:11:17.086 2264-9864 CCodec <my-package> I state->set(FLUSHED)
2022-11-22 17:11:17.087 2264-2521 MediaCodec <my-package> D keep callback message for reclaim
2022-11-22 17:11:17.087 2264-9864 CCodec <my-package> I state->set(RESUMING)
2022-11-22 17:11:17.087 2264-9864 CCodecConfig <my-package> I query failed after returning 19 values (BAD_INDEX)
2022-11-22 17:11:17.088 2264-9864 CCodec <my-package> I state->set(RUNNING)
2022-11-22 17:11:17.089 2264-9864 CCodec <my-package> I state->set(RELEASING)
2022-11-22 17:11:17.090 2264-9929 CCodec <my-package> I state->set(RELEASED)
2022-11-22 17:11:17.090 2264-9864 hw-BpHwBinder <my-package> I onLastStrongRef automatically unlinking death recipients
2022-11-22 17:11:17.090 2264-9864 MediaCodec <my-package> I Codec shutdown complete
2022-11-22 17:11:17.095 2264-2264 PlaybackService <my-package> D PlayerState: Idle
2022-11-22 17:11:17.097 2264-2476 ReactNativeJS <my-package> I 'STATE:', 'idle'
2022-11-22 17:11:17.097 2264-2264 PlaybackService <my-package> D PlayerState: Paused (Stopping and clearing)
2022-11-22 17:11:17.201 2264-2476 ReactNativeJS <my-package> I 'STATE:', 'paused'
2022-11-22 17:11:22.137 2264-2979 BufferPoolAccessor2.0 <my-package> D bufferpool2 0xb40000701c6606a8 : 0(0 size) total buffers - 0(0 size) used buffers - 311/316 (recycle/alloc) - 5/311 (fetch/transfer)
2022-11-22 17:11:22.137 2264-2979 BufferPoolAccessor2.0 <my-package> D evictor expired: 1, evicted: 1
流式传输时媒体 session 转储的 Pastebin: https://pastebin.com/5is1h2Mk
如果您认为有任何其他文件可能有助于找到答案,我会尝试提供,但我必须清理一些东西。
最佳答案
我遇到了同样的事情。您在媒体 session 上的播放状态需要调用 setState
。您只是在设置播放操作。
关于安卓汽车 : Media item gets stuck "Getting your selection..." instead of showing controls while playing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73340801/
所以我的应用程序的评论显示在我的游戏控制台中,但是由于某种原因,当我在 google Play 商店上访问我的应用程序链接并以普通用户的身份查看它时,我没有收到新评论的通知,我的显示了 13 条评论,
一旦我在 2.3 play 项目上运行 'sbt compile',我就不能再使用 'sbt compile' 来编译任何 Play 2.2.x 项目。这是我运行 sbt 命令时的错误。 [info]
我有点困惑,想得到一个解释。 我正在使用 Java Play 2 和 Akka Actor 。我使用 play run 启动系统。 不过,我刚刚看到一个视频,使用了命令: play akka star
当我玩游戏时,我遇到两个选择play.api.mvc和 play.mvc包裹 有什么不同? 最佳答案 从戏! 2 文档: The API available in the play.api packa
从 2.3 迁移到 2.4 后,我收到此错误。我应该使用的正确导入语句是什么? error: value routesImport is not a member of object play.Pla
所以我在 google play 上有一个应用程序已经将近 6 个月了,最近两个月我更新了我的应用程序屏幕截图,从那时起,每次我更新我的应用程序时,我都开始收到应用程序拒绝。 上次我提出上诉并被接受,
我有以下代码: Snapshots.OpenSnapshotResult result; result = Games.Snapshots.open(googleApiClient, "save",
在过去 72 小时内,我为 Google Play 开发者计划支付的 Google 电子钱包付款显示为“您的购买正在处理中”。我知道这可能需要长达 48 小时,但这是他们处理时间最坏情况之后的一整天。
我在 Play 商店发布了应用程序,我不知道为什么应用程序显示预注册,我想为我的用户提供直接下载选项。伸出援手将不胜感激。 最佳答案 instructions for pre-registration
我有一个 PHP 后端,它与 Google Play 服务集成以验证从 APP 进行的购买。购买信息返回收据和签名,我需要验证购买是否正确。 我收到: { ...rest of the data
我在 Google Play Developer Console 上创建了我的 Android 应用程序的草稿。我已经填写了所有需要的信息。必需的步骤之一是“内容评级”。我已填写表格以自动分配 Goo
我已经设置好了 com.typesafe.play play_2.13 2.7.4 在项目 pom.xml 中。但是,当我尝试遵循this tutorial时,语句 pla
我在 Play 商店上发布了一个应用程序,并收到了一些评论。在Google Play开发者控制台中,我在一些评论中看不到应用程序的版本。这是我在“应用程序”标题下找到的内容。 版本代码 — 版本名称
假设 A 是所有者。我希望我们团队的 B、C 和 D 用户能够上传我们应用程序的新版本。这可能吗?来自 this我不太清楚用户有什么样的权限。如果有人对这部分有任何经验,欢迎。 最佳答案 您需要 go
我正在尝试将应用重新提交到 Google Play,但我似乎可以找到一种技术上的方法来实现此目的。 我对“您的应用主要针对 COPPA 定义的 13 岁以下 child 吗?”的回答是肯定的,然后在不
我想分享一下我在分析 Google Play 控制台的新功能时遇到的情况,并尝试找到解决方案。 正如你们许多人可能已经知道的那样,Google 已在 Google Play 控制台上发布了更新并引入了
我有两个用 playframework 编写的应用程序。我想加入另一个。我有一个数据库,我想在它们之间共享我的登录类。应用程序对类、方法、变量使用不同的名称。 我怎样才能实现它?我应该创建 jar 版
对于我的硕士论文,我需要自动将来自 Google Play 的不同 Android 应用程序的信息写入一个文本文件。所以我使用 perl 脚本语言来实现这种自动化。我的 perl 脚本可以在 Goog
我想测试子项目是如何工作的,尤其是 routes在主项目 ( this was not visible before ) 中考虑了子项目的数量。 我在这里阅读了文档: https://github.c
我正在使用 Play 框架 2.1.2,我有一个 handlere 方法返回一个 Promise,如 Play 的 2.1.2 documentation 中所述 但是 Play 抛出编译错误说: C
我是一名优秀的程序员,十分优秀!