Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Androidでオーディオアプリを作るということ
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
rmakiyama
September 26, 2020
Technology
3.3k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Androidでオーディオアプリを作るということ
Androidでオーディオアプリを作るときに考慮すべきところなどを簡単に。
rmakiyama
September 26, 2020
More Decks by rmakiyama
See All by rmakiyama
UI State設計とテスト方針
rmakiyama
4
1.2k
KMPプロジェクトでマニュアルDIを使う選択
rmakiyama
0
550
Jetpack Composeとデザインシステム
rmakiyama
0
1.4k
TextField theme in Compose
rmakiyama
0
350
Androidエンジニアが1人という不安と向き合う
rmakiyama
6
7.1k
Jetpack Compose Canvas入門
rmakiyama
0
1.6k
HiltはDIをどうやってやっているのか
rmakiyama
1
350
Radiotalk Androidアプリにおけるモジュール分割の課題とこれから
rmakiyama
1
370
getChangePayload in DiffUtil
rmakiyama
0
3.4k
Other Decks in Technology
See All in Technology
社内の7割が使うデータ基盤を、 データチーム2人で回すためにやったこと
koh_yoshi
4
1.5k
Kiro入門|仕様駆動開発で変わるAI時代の開発スタイル
cmkudo
0
330
:syncing_time:
sksat
2
470
[potatotips #96] Give Your AI Agent the Flutter Playbook
korodroid
0
140
AIに持続⼒を与える 判断の⻑期記憶設計
eiei114
1
660
Kiro Crew で始める マルチエージェント開発
miu_crescent
PRO
0
160
ホームラボ紹介
y_sera15
0
230
コーチングの奥義 何もしないテクニック
jinwatanabe
0
150
【書籍出版記念】 10周回って、エージェント開発は RAGがすべてだった。〜RAGの歴史と開発現場で見えた実践知〜
akiratameto
17
6.4k
長期運営で肥大化したExcelマスターデータの解消に向けた移行事例
gree_tech
PRO
0
260
DatadogのBits Chatが開発組織にもたらしたもの / What Bits Chat Has Brought Us
sms_tech
1
300
医療の現場を変革に挑戦した半年間の軌跡 - PythonとAIで現場を変える / From Code to Care
soudai
PRO
1
570
Featured
See All Featured
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
380
For a Future-Friendly Web
brad_frost
183
10k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Designing Experiences People Love
moore
143
24k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
550
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
260
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
We Are The Robots
honzajavorek
0
310
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
Transcript
"OESPJEͰ ΦʔσΟΦΞϓϦΛ ࡞Δͱ͍͏͜ͱ Zli x ΤΩαΠτ ߹ಉLT 2020/09/26 ryo makiyama
ɹɹࣗݾհ •ࢁྎ •Radiotalkגࣜձࣾ •AndroidΤϯδχΞ • @_rmakiyama • rmakiyama
ԻΛ࠶ੜ͢Δ
ԻΛ࠶ੜ͢Δʹʁ • AudioTrack • SoundPool • MediaPlayer • ExoPlayer •
etc…
ԻΛ࠶ੜ͢Δʹʁ • AudioTrack • ੜͷԻσʔλΛѻ͑Δ • ࠷Ԇ͕গͳ͍ • ѻ͍͕͍͠… •
SoundPool • ͍Իʹద͍ͯ͠Δ • ޮՌԻͳͲ • ෛՙ͕͍ • Ԇ͕গͳ͍
ԻΛ࠶ੜ͢Δʹʁ • MediaPlayer • ࠷Ұൠత • ө૾ʹରԠ • ѻ͍͕؆୯ •
HLSະରԠ • ExoPlayer • GoogleͷϥΠϒϥϦ • ө૾ʹରԠ • ΧελϚΠζੑ͕ߴ͍ • HLSDASHʹରԠ
ExoPlayer val audioUri = Uri.parse(“https:"//sample.jp/media/media1.mp3”) val player = SimpleExoPlayer.Builder(context).build() val
sourceFactory = DefaultDataSourceFactory( context, Util.getUserAgent(context, "sample") ) val extractorsFactory = DefaultExtractorsFactory() val source = ProgressiveMediaSource.Factory(sourceFactory, extractorsFactory) .createMediaSource(audioUri) player.prepare(source)
؆୯
؆୯
ΦʔσΟΦΞϓϦʹٻΊΒΕΔ͜ͱ • όοΫάϥϯυͰ࠶ੜͰ͖Δ • ΠϠϗϯ͕ൈ͚ͨΒԻ͕ࢭ·Δ • ผͷΞϓϦͰԻΛ࠶ੜ͢Δͱఀࢭ͢Δ • ༷ʑͳσόΠε͔Βૢ࡞͕Ͱ͖Δ •
etc…
Ͳ͏ͬͯͬͯΔͷ
ΦʔσΟΦΞϓϦʹٻΊΒΕΔ͜ͱ • όοΫάϥϯυͰ࠶ੜͰ͖Δ • ΠϠϗϯ͕ൈ͚ͨΒԻ͕ࢭ·Δ • ผͷΞϓϦͰԻΛ࠶ੜ͢Δͱఀࢭ͢Δ • ༷ʑͳσόΠε͔Βૢ࡞͕Ͱ͖Δ •
etc… AndroidͷServiceΛར༻͢Δ
ΦʔσΟΦΞϓϦʹٻΊΒΕΔ͜ͱ • όοΫάϥϯυͰ࠶ੜͰ͖Δ • ΠϠϗϯ͕ൈ͚ͨΒԻ͕ࢭ·Δ • ผͷΞϓϦͰԻΛ࠶ੜ͢Δͱఀࢭ͢Δ • ༷ʑͳσόΠε͔Βૢ࡞͕Ͱ͖Δ •
etc… ExoPlayerઌੜ͕ͬͯ͘ΕΔ
ΦʔσΟΦΞϓϦʹٻΊΒΕΔ͜ͱ • όοΫάϥϯυͰ࠶ੜͰ͖Δ • ΠϠϗϯ͕ൈ͚ͨΒԻ͕ࢭ·Δ • ผͷΞϓϦͰԻΛ࠶ੜ͢Δͱఀࢭ͢Δ • ༷ʑͳσόΠε͔Βૢ࡞͕Ͱ͖Δ •
etc…
headset watch tv auto
༷ʑͳσόΠε͔Β ૢ࡞͞ΕΔ͜ͱΛ ఆ͢Δඞཁ͕͋Δ
ΦʔσΟΦΞϓϦͷਪΞʔΩςΫνϟ • ΫϥΠΞϯτ/αʔόʔઃܭ • ϝσΟΞίϯτϩʔϥʔ(ΫϥΠΞϯτ) • ϝσΟΞηογϣϯ(αʔόʔ) • UIʹΑΔૢ࡞ͱ ίϯςϯπใɾϓϨΠϠʔૢ࡞Λ͚ͨ
ref. https:"//developer.android.com/guide/topics/media-apps/media-apps-overview
UI/ϝσΟΞίϯτϩʔϥʔ(ΫϥΠΞϯτ) • UIίϯτϩʔϥʔͷΈͱΓͱΓ • ϓϨΠϠʔࣗମͱΓऔΓΛ͠ͳ͍ • ΞΫγϣϯηογϣϯͷίʔϧόοΫʹ • ۂใͷมߋͳͲηογϣϯ͔Β ίϯτϩʔϥʔ͕ίʔϧόοΫܗࣜͰड͚औΔ
ϝσΟΞηογϣϯ/ϓϨΠϠʔ(αʔόʔ) • 1ͭͷηογϣϯͰෳͷίϯτϩʔϥʔ͔Β ίʔϧόοΫΛड͚Δ͜ͱ͕Ͱ͖Δ • ϓϨΠϠʔηογϣϯ͔ΒͷΈૢ࡞͞ΕΔ • ίϯτϩʔϥʔ͔ΒͷίʔϧόοΫʹΑΓૢ࡞
ΦʔσΟΦΞϓϦ֓ཁ ref. https:"//developer.android.com/guide/topics/media-apps/media-apps-overview controller session player ui devices/controller
࣮ฤ%
ΦʔσΟΦΞϓϦ֓ཁʢ࣮دΓʣ ref. https:"//developer.android.com/guide/topics/media-apps/media-apps-overview
MediaBrowserService(session/player) class MyMediaService : MediaBrowserServiceCompat() { private lateinit var mediaSession:
MediaSessionCompat private lateinit var player: Player override fun onCreate() { super.onCreate() mediaSession = MediaSessionCompat(this, "MyMediaService").apply { … setCallback(myCallback) ɹɹɹɹɹɹ …
MediaBrowserService(session/player) override fun onCreate() { … } private val myCallback
= object : MediaSessionCompat.Callback() { override fun onPrepare() {} override fun onPlay() {} override fun onPause() {} override fun onStop() {} … }
MediaBrowserService(session/player) … override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints:
Bundle? ): BrowserRoot? { "// ଓ͞ΕͨΫϥΠΞϯτͷݕূΛ͢Δ "// ଓΛڋ൱͢Δͱ͖nullΛฦ͢ return BrowserRoot("root", null) }
MediaBrowserService(session/player) … override fun onLoadChildren( parentId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem">> )
{ "// ΫϥΠΞϯτʹϝσΟΞͷϦετΛฦ͢ val list = getMetadata() result.sendResult(list) } …
Activity(UI/controller) class MediaPlayerActivity : AppCompatActivity() { private lateinit var mediaBrowser:
MediaBrowserCompat private lateinit var mediaController: MediaControllerCompat override fun onCreate(savedInstanceState: Bundle?) { … mediaBrowser = MediaBrowserCompat( this, ComponentName(this, MyMediaService"::class.java), connectionCallbacks, null
Activity(UI/controller) class MediaPlayerActivity : AppCompatActivity() { private lateinit var mediaBrowser:
MediaBrowserCompat private lateinit var mediaController: MediaControllerCompat override fun onCreate(savedInstanceState: Bundle?) { … } override fun onStart() { super.onStart() "// MediaBrowserServiceʹଓ mediaBrowser.connect()
Activity(UI/controller) class MediaPlayerActivity : AppCompatActivity() { … private lateinit var
mediaController: MediaControllerCompat … private val connectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() { override fun onConnected() { "// sessionͷτʔΫϯ͔ΒcontrollerΛੜ mediaController = MediaControllerCompat(this@MediaPlayerActivity, mediaBrowser.sessionToken) .apply { registerCallback(controllerCallback) } "// UIͷૢ࡞ʹԠͯ͡controllerΛհͯ͠ΦʔσΟΦΛૢ࡞ "// ྫ) ࠶ੜɿmediaController.transportControls.play()
Activity(UI/controller) class MediaPlayerActivity : AppCompatActivity() { … private var controllerCallback
= object : MediaControllerCompat.Callback() { override fun onMetadataChanged(metadata: MediaMetadataCompat?) { "// ࠶ੜதͷίϯςϯπใͷมԽʹԠͯ͡UIΛߋ৽ } override fun onPlaybackStateChanged(state: PlaybackStateCompat?) { "// ࠶ੜͷঢ়ଶ(࠶ੜதఀࢭ)ͷมԽʹԠͯ͡UIΛߋ৽͢Δ } }
શʹཧղͨ͠ʁ
·ͱΊ •ԻΛ࠶ੜ͢Δ͚ͩͳΒ؆୯ʂ& •ΦʔσΟΦΞϓϦͰߟྀ͢Δ͜ͱҙ֎ͱଟ͍ • ࠓ͍ͯ͠ͳ͍͜ͱͨ͘͞Μ͋Δ…ʂ •ڵຯ͕༙͍ͨΒ࡞ͬͯΈΑ͏ʂ' • खΛಈ͔͢ͷେࣄʂ%