반응형
Chromecast
설명
- 애플리케이션에서 동영상을 Chromecast 디바이스에 연결하여 TV나 모니터로 송출하는 방법
- 과정중에 receiverApplicationId 설정이 필요한데 이는 Google Cast SDK Developer Console에 등록해서 발급받아야 한다.(유료인듯..?)
예제
build.gradledependencies {
...
implementation 'com.google.android.gms:play-services-cast-framework:17.0.0'
}
undefinedcopy
res/menu/main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/media_route_menu_item"
android:title="TEST"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always" />
</menu>
undefinedcopy
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickStart"
android:text="start" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickStop"
android:text="stop" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</ScrollView>
</LinearLayout>
undefinedcopy
MainActivity
class MainActivity : AppCompatActivity() {
private val castStateListener = CastStateListenerImpl()
private val sessionManagerListener = SessionManagerListenerImpl()
private lateinit var textView: TextView
private lateinit var castContext: CastContext
private lateinit var mediaRouteMenuItem: MenuItem
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.textView)
castContext = CastContext.getSharedInstance(this)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.main, menu)
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(applicationContext, menu, R.id.media_route_menu_item)
return true
}
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
return castContext.onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event)
}
override fun onResume() {
super.onResume()
castContext.addCastStateListener(castStateListener)
castContext.sessionManager.addSessionManagerListener(sessionManagerListener, CastSession::class.java)
}
override fun onPause() {
super.onPause()
castContext.removeCastStateListener(castStateListener)
castContext.sessionManager.removeSessionManagerListener(sessionManagerListener, CastSession::class.java)
}
fun onClickStart(view: View) {
val castSession = castContext.sessionManager.currentCastSession
if (castSession == null || !castSession.isConnected) {
showInfo("should enable chromecast")
return
}
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, "Google IO - 2014")
movieMetadata.putString(MediaMetadata.KEY_TITLE, "Designing For Google Cast")
movieMetadata.addImage(WebImage(Uri.parse("https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/images/480x270/DesigningForGoogleCast2-480x270.jpg")))
movieMetadata.addImage(WebImage(Uri.parse("https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/images/780x1200/DesigningForGoogleCast-887x1200.jpg")))
val mediaTrack = MediaTrack.Builder(1, 1)
.setName("English Subtitle")
.setSubtype(MediaTrack.SUBTYPE_CAPTIONS)
.setContentId("https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/tracks/DesigningForGoogleCast-en.vtt")
.setLanguage("en-US")
.build()
val mediaInfo = MediaInfo.Builder("https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/hls/DesigningForGoogleCast.m3u8")
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("application/x-mpegurl")
.setMetadata(movieMetadata)
.setMediaTracks(listOf(mediaTrack))
.setStreamDuration(333 * 1000)
// .setCustomData(jsonObj)
.build()
val remoteMediaClient = castSession.remoteMediaClient
remoteMediaClient.stop()
/*remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
override fun onStatusUpdated() {
startActivity(Intent(this@PlayerActivity, ExpandedControllerActivity::class.java))
remoteMediaClient.unregisterCallback(this)
}
})*/
remoteMediaClient.load(MediaLoadRequestData.Builder()
.setMediaInfo(mediaInfo)
// .setAutoplay(true)
.setCurrentTime(0)
.build())
remoteMediaClient.play()
}
fun onClickStop(view: View) {
val castSession = castContext.sessionManager.currentCastSession
if (castSession == null || !castSession.isConnected) {
showInfo("should enable chromecast")
return
}
val remoteMediaClient = castSession.remoteMediaClient
remoteMediaClient.stop()
}
private fun showInfo(message: String) {
textView.append("${message}\n\n")
}
private inner class CastStateListenerImpl : CastStateListener {
override fun onCastStateChanged(state: Int) {
if (state != CastState.NO_DEVICES_AVAILABLE) {
showInfo("[onCastStateChanged] state : ${state}")
}
}
}
private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession> {
override fun onSessionStarting(session: CastSession?) {
showInfo("[onSessionStarting] session : ${session}")
}
override fun onSessionStarted(session: CastSession?, sessionId: String?) {
showInfo("[onSessionStarted] session : ${session}, sessionId : ${sessionId}")
}
override fun onSessionStartFailed(session: CastSession?, error: Int) {
showInfo("[onSessionStartFailed] session : ${session}, error : ${error}")
}
override fun onSessionEnding(session: CastSession?) {
showInfo("[onSessionEnding] session : ${session}")
}
override fun onSessionEnded(session: CastSession?, error: Int) {
showInfo("[onSessionEnded] session : ${session}, error : ${error}")
}
override fun onSessionResuming(session: CastSession?, sessionId: String?) {
showInfo("[onSessionResuming] session : ${session}, sessionId : ${sessionId}")
}
override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) {
showInfo("[onSessionResumed] session : ${session}, wasSuspended : ${wasSuspended}")
}
override fun onSessionResumeFailed(session: CastSession?, error: Int) {
showInfo("[onSessionResumeFailed] session : ${session}, error : ${error}")
}
override fun onSessionSuspended(session: CastSession?, reason: Int) {
showInfo("[onSessionSuspended] session : ${session}, reason : ${reason}")
}
}
}
undefinedcopy
CastOptionsProvider
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
return CastOptions.Builder()
.setReceiverApplicationId("C0868879") // 테스트용 applicationId
.build()
}
override fun getAdditionalSessionProviders(context: Context): MutableList<SessionProvider>? {
return null
}
}
undefinedcopy
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.clone.android_chromecast">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Androidchromecast">
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.clone.android_chromecast.CastOptionsProvider" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity"
android:theme="@style/Theme.AppCompat.NoActionBar" />
</application>
</manifest>
undefinedcopy
참고
반응형
'Development > Android' 카테고리의 다른 글
[Android] NDK (0) | 2021.09.25 |
---|---|
[Android] Jenkins로 APK 빌드하기 (0) | 2021.02.22 |
[Android] ExoPlayer (0) | 2021.02.10 |
[Android] ViewTreeObserver (0) | 2021.02.10 |
[Android] LifecycleObserver (0) | 2021.02.10 |