Skip to content

Commit 5daf600

Browse files
authored
Merge pull request #6 from saschpe/example
Add example application
2 parents 3699e0b + 919a3dd commit 5daf600

25 files changed

+526
-0
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
*/
1616

1717
buildscript {
18+
ext.kotlin_version = '1.2.71'
19+
1820
repositories {
1921
jcenter()
2022
google()
2123
}
2224

2325
dependencies {
2426
classpath 'com.android.tools.build:gradle:3.2.0'
27+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
2528
}
2629
}
2730

example/build.gradle

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'kotlin-android'
3+
apply plugin: 'kotlin-android-extensions'
4+
5+
android {
6+
compileSdkVersion 28
7+
8+
defaultConfig {
9+
applicationId "com.example.exoplayer2.ext.icy"
10+
minSdkVersion 23
11+
targetSdkVersion 28
12+
versionCode 230100
13+
versionName "1.0.0"
14+
15+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16+
}
17+
}
18+
19+
dependencies {
20+
implementation project(':exoplayer2-ext-icy')
21+
implementation 'com.android.support:appcompat-v7:28.0.0'
22+
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
23+
implementation 'com.android.support:design:28.0.0'
24+
implementation 'com.google.android.exoplayer:exoplayer-core:2.8.4'
25+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
26+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.26.1'
27+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.26.1'
28+
29+
testImplementation 'junit:junit:4.12'
30+
31+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
32+
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.example.exoplayer2.ext.icy">
5+
6+
<uses-permission android:name="android.permission.INTERNET" />
7+
8+
<application
9+
android:allowBackup="true"
10+
android:icon="@mipmap/ic_launcher"
11+
android:label="@string/app_name"
12+
android:roundIcon="@mipmap/ic_launcher_round"
13+
android:supportsRtl="true"
14+
android:theme="@style/AppTheme"
15+
android:usesCleartextTraffic="true"
16+
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
17+
18+
<activity android:name=".MainActivity">
19+
<intent-filter>
20+
<action android:name="android.intent.action.MAIN" />
21+
22+
<category android:name="android.intent.category.LAUNCHER" />
23+
</intent-filter>
24+
</activity>
25+
26+
</application>
27+
28+
</manifest>
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package com.example.exoplayer2.ext.icy
2+
3+
import android.net.Uri
4+
import android.os.Bundle
5+
import android.support.v7.app.AppCompatActivity
6+
import android.util.Log
7+
import com.google.android.exoplayer2.*
8+
import com.google.android.exoplayer2.audio.AudioAttributes
9+
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
10+
import com.google.android.exoplayer2.source.ExtractorMediaSource
11+
import com.google.android.exoplayer2.source.TrackGroupArray
12+
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
13+
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
14+
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
15+
import com.google.android.exoplayer2.util.Util
16+
import kotlinx.android.synthetic.main.activity_main.*
17+
import kotlinx.coroutines.experimental.CoroutineStart
18+
import kotlinx.coroutines.experimental.Dispatchers
19+
import kotlinx.coroutines.experimental.GlobalScope
20+
import kotlinx.coroutines.experimental.async
21+
import saschpe.exoplayer2.ext.icy.IcyHttpDataSourceFactory
22+
23+
/**
24+
* Test application, doesn't necessarily show the best way to do things.
25+
*/
26+
class MainActivity : AppCompatActivity() {
27+
private var exoPlayer: SimpleExoPlayer? = null
28+
private val exoPlayerEventListener = ExoPlayerEventListener()
29+
private lateinit var userAgent: String
30+
private var isPlaying = false
31+
32+
override fun onCreate(savedInstanceState: Bundle?) {
33+
super.onCreate(savedInstanceState)
34+
setContentView(R.layout.activity_main)
35+
36+
stream.setText(DEFAULT_STREAM)
37+
38+
userAgent = Util.getUserAgent(applicationContext, applicationContext.getString(R.string.app_name))
39+
40+
play_pause.setOnClickListener {
41+
if (isPlaying) {
42+
stop()
43+
play_pause.setImageDrawable(resources.getDrawable(R.drawable.ic_play_arrow_black_24dp, null))
44+
} else {
45+
play()
46+
play_pause.setImageDrawable(resources.getDrawable(R.drawable.ic_stop_black_24dp, null))
47+
}
48+
}
49+
}
50+
51+
private fun play() {
52+
GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT, null, {
53+
if (exoPlayer == null) {
54+
exoPlayer = ExoPlayerFactory.newSimpleInstance(
55+
DefaultRenderersFactory(applicationContext),
56+
DefaultTrackSelector(),
57+
DefaultLoadControl()
58+
)
59+
exoPlayer?.addListener(exoPlayerEventListener)
60+
}
61+
62+
val audioAttributes = AudioAttributes.Builder()
63+
.setContentType(C.CONTENT_TYPE_MUSIC)
64+
.setUsage(C.USAGE_MEDIA)
65+
.build()
66+
exoPlayer?.audioAttributes = audioAttributes
67+
68+
// Custom HTTP data source factory which requests Icy metadata and parses it if
69+
// the stream server supports it
70+
val icyHttpDataSourceFactory = IcyHttpDataSourceFactory.Builder(userAgent)
71+
.setIcyHeadersListener { icyHeaders ->
72+
Log.d(TAG, "onIcyMetaData: icyHeaders=$icyHeaders")
73+
}
74+
.setIcyMetadataChangeListener { icyMetadata ->
75+
Log.d(TAG, "onIcyMetaData: icyMetadata=$icyMetadata")
76+
}
77+
.build()
78+
79+
// Produces DataSource instances through which media data is loaded
80+
val dataSourceFactory = DefaultDataSourceFactory(
81+
applicationContext, null, icyHttpDataSourceFactory
82+
)
83+
// Produces Extractor instances for parsing the media data
84+
val extractorsFactory = DefaultExtractorsFactory()
85+
86+
// The MediaSource represents the media to be played
87+
val mediaSource = ExtractorMediaSource.Factory(dataSourceFactory)
88+
.setExtractorsFactory(extractorsFactory)
89+
.createMediaSource(Uri.parse(stream.text.toString()))
90+
91+
// Prepares media to play (happens on background thread) and triggers
92+
// {@code onPlayerStateChanged} callback when the stream is ready to play
93+
exoPlayer?.prepare(mediaSource)
94+
})
95+
}
96+
97+
private fun stop() {
98+
releaseResources(true)
99+
isPlaying = false
100+
}
101+
102+
private fun releaseResources(releasePlayer: Boolean) {
103+
Log.d(TAG, "releaseResources: releasePlayer=$releasePlayer")
104+
105+
// Stops and releases player (if requested and available).
106+
if (releasePlayer && exoPlayer != null) {
107+
exoPlayer?.release()
108+
exoPlayer?.removeListener(exoPlayerEventListener)
109+
exoPlayer = null
110+
}
111+
}
112+
113+
private inner class ExoPlayerEventListener : Player.EventListener {
114+
override fun onTimelineChanged(timeline: Timeline, manifest: Any?, reason: Int) {
115+
}
116+
117+
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) {
118+
}
119+
120+
override fun onLoadingChanged(isLoading: Boolean) {
121+
}
122+
123+
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
124+
Log.i(TAG, "onPlayerStateChanged: playWhenReady=$playWhenReady, playbackState=$playbackState")
125+
when (playbackState) {
126+
Player.STATE_IDLE, Player.STATE_BUFFERING, Player.STATE_READY ->
127+
isPlaying = true
128+
Player.STATE_ENDED ->
129+
stop()
130+
}
131+
}
132+
133+
override fun onPlayerError(error: ExoPlaybackException) {
134+
Log.e(TAG, "onPlayerStateChanged: error=$error")
135+
}
136+
137+
override fun onPositionDiscontinuity(reason: Int) {
138+
}
139+
140+
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {
141+
}
142+
143+
override fun onSeekProcessed() {
144+
}
145+
146+
override fun onRepeatModeChanged(repeatMode: Int) {
147+
}
148+
149+
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
150+
}
151+
}
152+
153+
companion object {
154+
private const val TAG = "MainActivity"
155+
private const val DEFAULT_STREAM = "http://ice1.somafm.com/indiepop-128-mp3"
156+
}
157+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:aapt="http://schemas.android.com/aapt"
3+
android:width="108dp"
4+
android:height="108dp"
5+
android:viewportWidth="108"
6+
android:viewportHeight="108">
7+
<path
8+
android:fillType="evenOdd"
9+
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
10+
android:strokeWidth="1"
11+
android:strokeColor="#00000000">
12+
<aapt:attr name="android:fillColor">
13+
<gradient
14+
android:endX="78.5885"
15+
android:endY="90.9159"
16+
android:startX="48.7653"
17+
android:startY="61.0927"
18+
android:type="linear">
19+
<item
20+
android:color="#44000000"
21+
android:offset="0.0" />
22+
<item
23+
android:color="#00000000"
24+
android:offset="1.0" />
25+
</gradient>
26+
</aapt:attr>
27+
</path>
28+
<path
29+
android:fillColor="#FFFFFF"
30+
android:fillType="nonZero"
31+
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
32+
android:strokeWidth="1"
33+
android:strokeColor="#00000000" />
34+
</vector>

0 commit comments

Comments
 (0)