SlideShare a Scribd company logo
The Sounds of
Android
Let’s make some noise!
Android Makers 2018
Noise generator:
Yannick Lemin
• Android developer freelance

• GDG Brussels Organizer

• @android_leaks

• Noise Maker

• @theyann
Disclaimer
In the beginning…
d
So let’s make a fart
app…
So let’s make a fart
app…
…in 4 steps
Step 1 - Create a
new app
Step 1 - Create a
new app
Step 1 - Create a
new app
#Kotlin
Step 2 - Add a
button to the layout
Step 3 - Recording
Step 3 - Recording
Step 3.5 - Drop the
file in the project
Step 4 - Play the Media
Step 4 - Play the Media
MediaPlayer
Step 4.1 - MediaPlayer
class MainActivity : AppCompatActivity() {
private var player: MediaPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
findViewById<View>(R.id.button_play).setOnClickListener { play() }
}
override fun onStop() {
super.onStop()
player?.release()
}
private fun play() {
player?.release()
player = MediaPlayer.create(this, R.raw.best_fart_ever).apply {
setOnCompletionListener { release() }
start()
}
}
}
MediaPlayer
• Very simple to use

• Exists since API1

• Handles resources, over
the network streaming,
even with DRM
PROS
MediaPlayer
• Very simple to use

• Exists since API1

• Handles resources, over
the network streaming,
even with DRM
PROS
• Not extensible

• Dependent on OS for bug
fixes and new features
CONS
Step 4 - Play the Media
ExoPlayer
Step 4 - Play the Media
class MainActivity : AppCompatActivity() {
private lateinit var player: ExoPlayer
override fun onCreate(savedInstanceState: Bundle?) {
...
player = ExoPlayerFactory.newSimpleInstance(this, DefaultTrackSelector())
}
...
private fun play() {
stop()
with (player) {
val source = ExtractorMediaSource.Factory(
DefaultDataSourceFactory(this@MainActivity, "fartheaven")
).createMediaSource(Uri.parse("asset:///best_fart_ever.m4a"))
prepare(source)
playWhenReady = true
}
}
}
Step 4.2 - ExoPlayer
ExoPlayer
• Much more flexible and
extensible

• Better suited for complex
use cases

• External library

• Handles caching, adaptive
playback, composition, etc
PROS
ExoPlayer
• Much more flexible and
extensible

• Better suited for complex
use cases

• External library

• Handles caching, adaptive
playback, composition, etc
PROS
• More complex to
apprehend

• MinSdk 16 (or 19 for
encryption support)

• Big library
CONS
Step 4 - Play the Media
Step 4 - Play the Media
SoundPool
Step 4 - Play the Media
SoundPool
… a pool full of sound?
private fun initSoundPool() {
soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
SoundPool(1, AudioManager.STREAM_MUSIC, 0)
} else {
val attributes = AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION)
.build()
SoundPool.Builder()
.setAudioAttributes(attributes.unwrap() as AudioAttributes)
.setMaxStreams(1)
.build()
}
soundPool.setOnLoadCompleteListener({ _, _, status ->
loadComplete = status == 0
if (loadComplete) { play() }
})
soundId = soundPool.load(this, R.raw.best_fart_ever, 1)
}
Step 4.3 - SoundPool
private fun initSoundPool() {
soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
SoundPool(1, AudioManager.STREAM_MUSIC, 0)
} else {
val attributes = AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION)
.build()
SoundPool.Builder()
.setAudioAttributes(attributes.unwrap() as AudioAttributes)
.setMaxStreams(1)
.build()
}
soundPool.setOnLoadCompleteListener({ _, _, status ->
loadComplete = status == 0
if (loadComplete) { play() }
})
soundId = soundPool.load(this, R.raw.best_fart_ever, 1)
}
Step 4.3 - SoundPool
private fun initSoundPool() {
soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
SoundPool(1, AudioManager.STREAM_MUSIC, 0)
} else {
val attributes = AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION)
.build()
SoundPool.Builder()
.setAudioAttributes(attributes.unwrap() as AudioAttributes)
.setMaxStreams(1)
.build()
}
soundPool.setOnLoadCompleteListener({ _, _, status ->
loadComplete = status == 0
if (loadComplete) { play() }
})
soundId = soundPool.load(this, R.raw.best_fart_ever, 1)
}
Step 4.3 - SoundPool
private fun initSoundPool() {
soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
SoundPool(1, AudioManager.STREAM_MUSIC, 0)
} else {
val attributes = AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION)
.build()
SoundPool.Builder()
.setAudioAttributes(attributes.unwrap() as AudioAttributes)
.setMaxStreams(1)
.build()
}
soundPool.setOnLoadCompleteListener({ _, _, status ->
loadComplete = status == 0
if (loadComplete) { play() }
})
soundId = soundPool.load(this, R.raw.best_fart_ever, 1)
}
Step 4.3 - SoundPool
private fun play() {
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val actualVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
val volume = (actualVolume / maxVolume).toFloat()
soundPool.play(soundId, volume, volume, priority, loopCount, speed)
}
Step 4.3 - SoundPool
Speaking of
recording …
MediaRecorder
MediaRecorder
fileName = "${externalCacheDir.absolutePath}/best_fart_ever.3gp"
private fun record() {
recorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
setOutputFile(fileName)
setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
try {
prepare()
start()
} catch (e: IOException) {
release()
}
}
}
To play it back
private fun play() {
player = MediaPlayer().apply {
try {
setOnCompletionListener { this@MainActivity.stop() }
setDataSource(fileName)
prepare()
start()
} catch (e: IOException) {
release()
}
}
}
AudioFocus
AudioFocus
…or how to make your audio app
not be a jackass and work well
with the platform
AudioFocus
Your App
Without
AudioFocus
Your App
Without
AudioFocus
Your App
Without
AudioFocus
Your App
Without
AudioFocus
Your App
With
AudioFocus
Your App
With
AudioFocus
Your App
With
AudioFocus
Your App
With
AudioFocus
Your App
With
1. You need a
listener
class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
when(focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
// start playing or reset volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// reduce volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// pause without dropping focus
}
AudioManager.AUDIOFOCUS_LOSS -> {
// focus was lost
}
}
}
}
1. You need a
listener
class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
when(focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
// start playing or reset volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// reduce volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// pause without dropping focus
}
AudioManager.AUDIOFOCUS_LOSS -> {
// focus was lost
}
}
}
}
1. You need a
listener
class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
when(focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
// start playing or reset volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// reduce volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// pause without dropping focus
}
AudioManager.AUDIOFOCUS_LOSS -> {
// focus was lost
}
}
}
}
1. You need a
listener
class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
when(focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
// start playing or reset volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// reduce volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// pause without dropping focus
}
AudioManager.AUDIOFOCUS_LOSS -> {
// focus was lost
}
}
}
}
1. You need a
listener
class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
when(focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
// start playing or reset volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// reduce volume
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// pause without dropping focus
}
AudioManager.AUDIOFOCUS_LOSS -> {
// focus was lost
}
}
}
}
2. Request the focus
private fun requestAudioFocus() {
audioFocusListener = AudioFocusListener(…)
val requestResult = audioManager.requestAudioFocus(audioFocusListener,
AudioManager.STREAM_MUSIC
AudioManager.AUDIOFOCUS_GAIN)
if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// start playing
} else {
// handle error
}
}
2. Request the focus
… API >= 26
val attributes = AudioAttributesCompat.Builder()
.setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.build()
// keep the request around
request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(attributes.unwrap as AudioAttributes)
.setOnAudioFocusChangeListener(audioFocusListener)
.build()
audioManager.requestAudioFocus(request)
Content Type and Usage
AudioAttributesCompat.CONTENT_TYPE_SPEECH
AudioAttributesCompat.CONTENT_TYPE_MUSIC
AudioAttributesCompat.CONTENT_TYPE_MOVIE
AudioAttributesCompat.CONTENT_TYPE_SONIFICATION
AudioAttributesCompat.USAGE_MEDIA
AudioAttributesCompat.USAGE_VOICE_COMMUNICATION
AudioAttributesCompat.USAGE_VOICE_COMMUNICATION_SIGNALLING
AudioAttributesCompat.USAGE_ALARM
AudioAttributesCompat.USAGE_NOTIFICATION
AudioAttributesCompat.USAGE_NOTIFICATION_RINGTONE
AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_REQUEST
AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_INSTANT
AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_DELAYED
AudioAttributesCompat.USAGE_NOTIFICATION_EVENT
AudioAttributesCompat.USAGE_ASSISTANCE_ACCESSIBILITY
AudioAttributesCompat.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
AudioAttributesCompat.USAGE_ASSISTANCE_SONIFICATION
AudioAttributesCompat.USAGE_GAME
AudioAttributesCompat.USAGE_VIRTUAL_SOURCE
AudioAttributesCompat.USAGE_ASSISTANT
3. Abandon when
you’re done
// API < 26
audioManager.abandonAudioFocus(audioFocusListener)
// API >= 26
audioManager.abandonAudioFocusRequest(request)
And how about a more
complex audio app?
MediaSession
MediaSession
…or how to control your
stream from anything
MediaSession
Source: https://medium.com/google-developers/understanding-mediasession-part-2-4-ad291fd32d60
MediaBrowserService
MediaBrowserService
…or how to expose your media
to the rest of the ecosystem
MediaBrowserService
…or how to expose your media
to the rest of the ecosystem
#ecosystem
Source : https://medium.com/google-developers/understanding-mediasession-part-4-4-dcc77c535f99
Source : https://medium.com/google-developers/understanding-mediasession-part-4-4-dcc77c535f99
Source : https://medium.com/google-developers/understanding-mediasession-part-4-4-dcc77c535f99
Source : https://medium.com/google-developers/understanding-mediasession-part-4-4-dcc77c535f99
Going Deeper…
AudioTrack
AudioTrack
… The lower level
MediaPlayer
AudioTrack API < 26
AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, // most likely 44.1 Khz
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
numberOfSamples,
AudioTrack.MODE_STATIC)
AudioTrack.Builder()
.setAudioAttributes(AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC)
.build())
.setAudioFormat(AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(sampleRate) // most likely 44.1Khz
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build())
.setBufferSizeInBytes(bufferSize)
.build()
AudioTrack API >= 26
AudioTrack usage
fun play() {
val audioTrack = initAudioTrack()
val someSoundDataInByteArray = getSoundDataSomewhere()
audioTrack.write(someSoundsInByteArray, startOffset, bufferSize)
}
AudioRecord
AudioRecord
… The lower level
MediaRecorder
AudioEffect
AudioEffect
… applies effects on
audio!
Build-in Effects
• Equalizer

• Virtualizer

• BassBoost

• PresetReverb

• EnvironmentalReverb
Effect Usage
val reverb = PresetReverb(priority, audioSession).apply {
preset = PresetReverb.PRESET_LARGEHALL
enabled = true
...
}
audioTrack.apply {
attachAuxEffect(reverb.id)
setAuxEffectSendLevel(1.0F)
...
}
Standard
Standard
https://www.khronos.org/opensles/
Alternative SDK
https://superpowered.com
Last but not least
Last but not least
How does it work
How does it work
Controller
How does it work
Controller
Interface
How does it work
Controller
Computer
Interface
How does it work
Controller
Computer
Controller
Interface
How does it work
Controller
Computer
Controller
Interface
Controller
How does it work
Controller
Computer
Controller
Interface
Controller
On Android
THANK YOU :)
Good Reads
• Understanding MediaSession http://bit.ly/mediasession

• Building a Video Player app in Android http://bit.ly/
vplayerandroid

• ADB Podcast Episode 85 Focus on Audio http://bit.ly/
adbaudiofocus

• Styling Android’s MIDI posts http://bit.ly/midiandroid

More Related Content

Similar to The sounds of Android (Android Makers 2018)

Best Practices in Media Playback
Best Practices in Media PlaybackBest Practices in Media Playback
Best Practices in Media Playback
Hassan Abid
 
Android Audio & OpenSL
Android Audio & OpenSLAndroid Audio & OpenSL
Android Audio & OpenSL
Yoss Cohen
 
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
dgmit2009
 
Core audio
Core audioCore audio
Core audio
scussen
 
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
Amazon Appstore Developers
 
Exoplayer 2
Exoplayer  2Exoplayer  2
Exoplayer 2
TSE-JU LIN(Louis)
 
Flash runtime on mobile
Flash runtime on mobileFlash runtime on mobile
Flash runtime on mobile
howard-wu
 
Designing of media player
Designing of media playerDesigning of media player
Designing of media player
Nur Islam
 
Android media
Android mediaAndroid media
Android media
Krazy Koder
 
Get On The Audiobus (CocoaConf Atlanta, November 2013)
Get On The Audiobus (CocoaConf Atlanta, November 2013)Get On The Audiobus (CocoaConf Atlanta, November 2013)
Get On The Audiobus (CocoaConf Atlanta, November 2013)
Chris Adamson
 
Best Practices in Media Playback
Best Practices in Media PlaybackBest Practices in Media Playback
Best Practices in Media Playback
GDG Korea
 
Get On The Audiobus (CocoaConf Boston, October 2013)
Get On The Audiobus (CocoaConf Boston, October 2013)Get On The Audiobus (CocoaConf Boston, October 2013)
Get On The Audiobus (CocoaConf Boston, October 2013)
Chris Adamson
 
J2me
J2meJ2me
J2me
My Đá
 
KKBOX WWDC17 Airplay 2 - Dolphin
KKBOX WWDC17 Airplay 2 - DolphinKKBOX WWDC17 Airplay 2 - Dolphin
KKBOX WWDC17 Airplay 2 - Dolphin
Liyao Chen
 
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger, Greenrobot
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger,  GreenrobotDroidcon 2011: Gingerbread and honeycomb, Markus Junginger,  Greenrobot
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger, Greenrobot
Droidcon Berlin
 
Android media-chapter 23
Android media-chapter 23Android media-chapter 23
Android media-chapter 23
Dr. Ramkumar Lakshminarayanan
 
The Study For A Sound Engineering And Recording Class
The Study For A Sound Engineering And Recording ClassThe Study For A Sound Engineering And Recording Class
The Study For A Sound Engineering And Recording Class
Reggie621
 
Qditor user guide for windows pc
Qditor user guide for windows pcQditor user guide for windows pc
Qditor user guide for windows pc
Qditor Video Editor
 
Audio equalizer
Audio equalizerAudio equalizer
Audio equalizer
Hasham khan
 
Audio Post Production
Audio Post ProductionAudio Post Production
Audio Post Production
Joe Nasr
 

Similar to The sounds of Android (Android Makers 2018) (20)

Best Practices in Media Playback
Best Practices in Media PlaybackBest Practices in Media Playback
Best Practices in Media Playback
 
Android Audio & OpenSL
Android Audio & OpenSLAndroid Audio & OpenSL
Android Audio & OpenSL
 
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
제 5회 DGMIT R&D 컨퍼런스: Sound Module With OperSLEs
 
Core audio
Core audioCore audio
Core audio
 
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
 
Exoplayer 2
Exoplayer  2Exoplayer  2
Exoplayer 2
 
Flash runtime on mobile
Flash runtime on mobileFlash runtime on mobile
Flash runtime on mobile
 
Designing of media player
Designing of media playerDesigning of media player
Designing of media player
 
Android media
Android mediaAndroid media
Android media
 
Get On The Audiobus (CocoaConf Atlanta, November 2013)
Get On The Audiobus (CocoaConf Atlanta, November 2013)Get On The Audiobus (CocoaConf Atlanta, November 2013)
Get On The Audiobus (CocoaConf Atlanta, November 2013)
 
Best Practices in Media Playback
Best Practices in Media PlaybackBest Practices in Media Playback
Best Practices in Media Playback
 
Get On The Audiobus (CocoaConf Boston, October 2013)
Get On The Audiobus (CocoaConf Boston, October 2013)Get On The Audiobus (CocoaConf Boston, October 2013)
Get On The Audiobus (CocoaConf Boston, October 2013)
 
J2me
J2meJ2me
J2me
 
KKBOX WWDC17 Airplay 2 - Dolphin
KKBOX WWDC17 Airplay 2 - DolphinKKBOX WWDC17 Airplay 2 - Dolphin
KKBOX WWDC17 Airplay 2 - Dolphin
 
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger, Greenrobot
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger,  GreenrobotDroidcon 2011: Gingerbread and honeycomb, Markus Junginger,  Greenrobot
Droidcon 2011: Gingerbread and honeycomb, Markus Junginger, Greenrobot
 
Android media-chapter 23
Android media-chapter 23Android media-chapter 23
Android media-chapter 23
 
The Study For A Sound Engineering And Recording Class
The Study For A Sound Engineering And Recording ClassThe Study For A Sound Engineering And Recording Class
The Study For A Sound Engineering And Recording Class
 
Qditor user guide for windows pc
Qditor user guide for windows pcQditor user guide for windows pc
Qditor user guide for windows pc
 
Audio equalizer
Audio equalizerAudio equalizer
Audio equalizer
 
Audio Post Production
Audio Post ProductionAudio Post Production
Audio Post Production
 

Recently uploaded

The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
The Intersection between Competition and Data Privacy – COLANGELO – June 2024...The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
OECD Directorate for Financial and Enterprise Affairs
 
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussionArtificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
OECD Directorate for Financial and Enterprise Affairs
 
ASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdfASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdf
ToshihiroIto4
 
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussion
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussionPro-competitive Industrial Policy – LANE – June 2024 OECD discussion
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussion
OECD Directorate for Financial and Enterprise Affairs
 
The remarkable life of Sir Mokshagundam Visvesvaraya.pptx
The remarkable life of Sir Mokshagundam Visvesvaraya.pptxThe remarkable life of Sir Mokshagundam Visvesvaraya.pptx
The remarkable life of Sir Mokshagundam Visvesvaraya.pptx
JiteshKumarChoudhary2
 
Disaster Management project for holidays homework and other uses
Disaster Management project for holidays homework and other usesDisaster Management project for holidays homework and other uses
Disaster Management project for holidays homework and other uses
RIDHIMAGARG21
 
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
OECD Directorate for Financial and Enterprise Affairs
 
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussion
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussionPro-competitive Industrial Policy – OECD – June 2024 OECD discussion
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussion
OECD Directorate for Financial and Enterprise Affairs
 
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
OECD Directorate for Financial and Enterprise Affairs
 
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
kekzed
 
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
OECD Directorate for Financial and Enterprise Affairs
 
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdfWhy Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
Ben Linders
 
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussionArtificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
OECD Directorate for Financial and Enterprise Affairs
 
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
OECD Directorate for Financial and Enterprise Affairs
 
Carrer goals.pptx and their importance in real life
Carrer goals.pptx  and their importance in real lifeCarrer goals.pptx  and their importance in real life
Carrer goals.pptx and their importance in real life
artemacademy2
 
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij
 
XP 2024 presentation: A New Look to Leadership
XP 2024 presentation: A New Look to LeadershipXP 2024 presentation: A New Look to Leadership
XP 2024 presentation: A New Look to Leadership
samililja
 
IEEE CIS Webinar Sustainable futures.pdf
IEEE CIS Webinar Sustainable futures.pdfIEEE CIS Webinar Sustainable futures.pdf
IEEE CIS Webinar Sustainable futures.pdf
Claudio Gallicchio
 
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
OECD Directorate for Financial and Enterprise Affairs
 
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
gpww3sf4
 

Recently uploaded (20)

The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
The Intersection between Competition and Data Privacy – COLANGELO – June 2024...The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
The Intersection between Competition and Data Privacy – COLANGELO – June 2024...
 
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussionArtificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – OECD – June 2024 OECD discussion
 
ASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdfASONAM2023_presection_slide_track-recommendation.pdf
ASONAM2023_presection_slide_track-recommendation.pdf
 
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussion
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussionPro-competitive Industrial Policy – LANE – June 2024 OECD discussion
Pro-competitive Industrial Policy – LANE – June 2024 OECD discussion
 
The remarkable life of Sir Mokshagundam Visvesvaraya.pptx
The remarkable life of Sir Mokshagundam Visvesvaraya.pptxThe remarkable life of Sir Mokshagundam Visvesvaraya.pptx
The remarkable life of Sir Mokshagundam Visvesvaraya.pptx
 
Disaster Management project for holidays homework and other uses
Disaster Management project for holidays homework and other usesDisaster Management project for holidays homework and other uses
Disaster Management project for holidays homework and other uses
 
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
Competition and Regulation in Professions and Occupations – OECD – June 2024 ...
 
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussion
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussionPro-competitive Industrial Policy – OECD – June 2024 OECD discussion
Pro-competitive Industrial Policy – OECD – June 2024 OECD discussion
 
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
The Intersection between Competition and Data Privacy – KEMP – June 2024 OECD...
 
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
怎么办理(lincoln学位证书)英国林肯大学毕业证文凭学位证书原版一模一样
 
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
Artificial Intelligence, Data and Competition – SCHREPEL – June 2024 OECD dis...
 
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdfWhy Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
Why Psychological Safety Matters for Software Teams - ACE 2024 - Ben Linders.pdf
 
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussionArtificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
Artificial Intelligence, Data and Competition – LIM – June 2024 OECD discussion
 
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
Artificial Intelligence, Data and Competition – ČORBA – June 2024 OECD discus...
 
Carrer goals.pptx and their importance in real life
Carrer goals.pptx  and their importance in real lifeCarrer goals.pptx  and their importance in real life
Carrer goals.pptx and their importance in real life
 
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
Suzanne Lagerweij - Influence Without Power - Why Empathy is Your Best Friend...
 
XP 2024 presentation: A New Look to Leadership
XP 2024 presentation: A New Look to LeadershipXP 2024 presentation: A New Look to Leadership
XP 2024 presentation: A New Look to Leadership
 
IEEE CIS Webinar Sustainable futures.pdf
IEEE CIS Webinar Sustainable futures.pdfIEEE CIS Webinar Sustainable futures.pdf
IEEE CIS Webinar Sustainable futures.pdf
 
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
The Intersection between Competition and Data Privacy – OECD – June 2024 OECD...
 
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
原版制作贝德福特大学毕业证(bedfordhire毕业证)硕士文凭原版一模一样
 

The sounds of Android (Android Makers 2018)

  • 1. The Sounds of Android Let’s make some noise! Android Makers 2018
  • 2. Noise generator: Yannick Lemin • Android developer freelance • GDG Brussels Organizer • @android_leaks • Noise Maker • @theyann
  • 5. d
  • 6. So let’s make a fart app…
  • 7. So let’s make a fart app… …in 4 steps
  • 8. Step 1 - Create a new app
  • 9. Step 1 - Create a new app
  • 10. Step 1 - Create a new app #Kotlin
  • 11. Step 2 - Add a button to the layout
  • 12. Step 3 - Recording
  • 13. Step 3 - Recording
  • 14. Step 3.5 - Drop the file in the project
  • 15. Step 4 - Play the Media
  • 16. Step 4 - Play the Media MediaPlayer
  • 17. Step 4.1 - MediaPlayer class MainActivity : AppCompatActivity() { private var player: MediaPlayer? = null override fun onCreate(savedInstanceState: Bundle?) { ... findViewById<View>(R.id.button_play).setOnClickListener { play() } } override fun onStop() { super.onStop() player?.release() } private fun play() { player?.release() player = MediaPlayer.create(this, R.raw.best_fart_ever).apply { setOnCompletionListener { release() } start() } } }
  • 18. MediaPlayer • Very simple to use • Exists since API1 • Handles resources, over the network streaming, even with DRM PROS
  • 19. MediaPlayer • Very simple to use • Exists since API1 • Handles resources, over the network streaming, even with DRM PROS • Not extensible • Dependent on OS for bug fixes and new features CONS
  • 20. Step 4 - Play the Media
  • 21. ExoPlayer Step 4 - Play the Media
  • 22. class MainActivity : AppCompatActivity() { private lateinit var player: ExoPlayer override fun onCreate(savedInstanceState: Bundle?) { ... player = ExoPlayerFactory.newSimpleInstance(this, DefaultTrackSelector()) } ... private fun play() { stop() with (player) { val source = ExtractorMediaSource.Factory( DefaultDataSourceFactory(this@MainActivity, "fartheaven") ).createMediaSource(Uri.parse("asset:///best_fart_ever.m4a")) prepare(source) playWhenReady = true } } } Step 4.2 - ExoPlayer
  • 23. ExoPlayer • Much more flexible and extensible • Better suited for complex use cases • External library • Handles caching, adaptive playback, composition, etc PROS
  • 24. ExoPlayer • Much more flexible and extensible • Better suited for complex use cases • External library • Handles caching, adaptive playback, composition, etc PROS • More complex to apprehend • MinSdk 16 (or 19 for encryption support) • Big library CONS
  • 25. Step 4 - Play the Media
  • 26. Step 4 - Play the Media SoundPool
  • 27. Step 4 - Play the Media SoundPool … a pool full of sound?
  • 28. private fun initSoundPool() { soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { SoundPool(1, AudioManager.STREAM_MUSIC, 0) } else { val attributes = AudioAttributesCompat.Builder() .setUsage(AudioAttributesCompat.USAGE_MEDIA) .setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION) .build() SoundPool.Builder() .setAudioAttributes(attributes.unwrap() as AudioAttributes) .setMaxStreams(1) .build() } soundPool.setOnLoadCompleteListener({ _, _, status -> loadComplete = status == 0 if (loadComplete) { play() } }) soundId = soundPool.load(this, R.raw.best_fart_ever, 1) } Step 4.3 - SoundPool
  • 29. private fun initSoundPool() { soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { SoundPool(1, AudioManager.STREAM_MUSIC, 0) } else { val attributes = AudioAttributesCompat.Builder() .setUsage(AudioAttributesCompat.USAGE_MEDIA) .setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION) .build() SoundPool.Builder() .setAudioAttributes(attributes.unwrap() as AudioAttributes) .setMaxStreams(1) .build() } soundPool.setOnLoadCompleteListener({ _, _, status -> loadComplete = status == 0 if (loadComplete) { play() } }) soundId = soundPool.load(this, R.raw.best_fart_ever, 1) } Step 4.3 - SoundPool
  • 30. private fun initSoundPool() { soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { SoundPool(1, AudioManager.STREAM_MUSIC, 0) } else { val attributes = AudioAttributesCompat.Builder() .setUsage(AudioAttributesCompat.USAGE_MEDIA) .setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION) .build() SoundPool.Builder() .setAudioAttributes(attributes.unwrap() as AudioAttributes) .setMaxStreams(1) .build() } soundPool.setOnLoadCompleteListener({ _, _, status -> loadComplete = status == 0 if (loadComplete) { play() } }) soundId = soundPool.load(this, R.raw.best_fart_ever, 1) } Step 4.3 - SoundPool
  • 31. private fun initSoundPool() { soundPool = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { SoundPool(1, AudioManager.STREAM_MUSIC, 0) } else { val attributes = AudioAttributesCompat.Builder() .setUsage(AudioAttributesCompat.USAGE_MEDIA) .setContentType(AudioAttributesCompat.CONTENT_TYPE_SONIFICATION) .build() SoundPool.Builder() .setAudioAttributes(attributes.unwrap() as AudioAttributes) .setMaxStreams(1) .build() } soundPool.setOnLoadCompleteListener({ _, _, status -> loadComplete = status == 0 if (loadComplete) { play() } }) soundId = soundPool.load(this, R.raw.best_fart_ever, 1) } Step 4.3 - SoundPool
  • 32. private fun play() { val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager val actualVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) val volume = (actualVolume / maxVolume).toFloat() soundPool.play(soundId, volume, volume, priority, loopCount, speed) } Step 4.3 - SoundPool
  • 35. MediaRecorder fileName = "${externalCacheDir.absolutePath}/best_fart_ever.3gp" private fun record() { recorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP) setOutputFile(fileName) setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) try { prepare() start() } catch (e: IOException) { release() } } }
  • 36. To play it back private fun play() { player = MediaPlayer().apply { try { setOnCompletionListener { this@MainActivity.stop() } setDataSource(fileName) prepare() start() } catch (e: IOException) { release() } } }
  • 38. AudioFocus …or how to make your audio app not be a jackass and work well with the platform
  • 48. 1. You need a listener class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener { override fun onAudioFocusChange(focusChange: Int) { when(focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // start playing or reset volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // reduce volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // pause without dropping focus } AudioManager.AUDIOFOCUS_LOSS -> { // focus was lost } } } }
  • 49. 1. You need a listener class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener { override fun onAudioFocusChange(focusChange: Int) { when(focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // start playing or reset volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // reduce volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // pause without dropping focus } AudioManager.AUDIOFOCUS_LOSS -> { // focus was lost } } } }
  • 50. 1. You need a listener class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener { override fun onAudioFocusChange(focusChange: Int) { when(focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // start playing or reset volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // reduce volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // pause without dropping focus } AudioManager.AUDIOFOCUS_LOSS -> { // focus was lost } } } }
  • 51. 1. You need a listener class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener { override fun onAudioFocusChange(focusChange: Int) { when(focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // start playing or reset volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // reduce volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // pause without dropping focus } AudioManager.AUDIOFOCUS_LOSS -> { // focus was lost } } } }
  • 52. 1. You need a listener class AudioFocusListener(...) : AudioManager.OnAudioFocusChangeListener { override fun onAudioFocusChange(focusChange: Int) { when(focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // start playing or reset volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // reduce volume } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // pause without dropping focus } AudioManager.AUDIOFOCUS_LOSS -> { // focus was lost } } } }
  • 53. 2. Request the focus private fun requestAudioFocus() { audioFocusListener = AudioFocusListener(…) val requestResult = audioManager.requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC AudioManager.AUDIOFOCUS_GAIN) if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // start playing } else { // handle error } }
  • 54. 2. Request the focus … API >= 26 val attributes = AudioAttributesCompat.Builder() .setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributesCompat.USAGE_MEDIA) .build() // keep the request around request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(attributes.unwrap as AudioAttributes) .setOnAudioFocusChangeListener(audioFocusListener) .build() audioManager.requestAudioFocus(request)
  • 55. Content Type and Usage AudioAttributesCompat.CONTENT_TYPE_SPEECH AudioAttributesCompat.CONTENT_TYPE_MUSIC AudioAttributesCompat.CONTENT_TYPE_MOVIE AudioAttributesCompat.CONTENT_TYPE_SONIFICATION AudioAttributesCompat.USAGE_MEDIA AudioAttributesCompat.USAGE_VOICE_COMMUNICATION AudioAttributesCompat.USAGE_VOICE_COMMUNICATION_SIGNALLING AudioAttributesCompat.USAGE_ALARM AudioAttributesCompat.USAGE_NOTIFICATION AudioAttributesCompat.USAGE_NOTIFICATION_RINGTONE AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_REQUEST AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_INSTANT AudioAttributesCompat.USAGE_NOTIFICATION_COMMUNICATION_DELAYED AudioAttributesCompat.USAGE_NOTIFICATION_EVENT AudioAttributesCompat.USAGE_ASSISTANCE_ACCESSIBILITY AudioAttributesCompat.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE AudioAttributesCompat.USAGE_ASSISTANCE_SONIFICATION AudioAttributesCompat.USAGE_GAME AudioAttributesCompat.USAGE_VIRTUAL_SOURCE AudioAttributesCompat.USAGE_ASSISTANT
  • 56. 3. Abandon when you’re done // API < 26 audioManager.abandonAudioFocus(audioFocusListener) // API >= 26 audioManager.abandonAudioFocusRequest(request)
  • 57. And how about a more complex audio app?
  • 59. MediaSession …or how to control your stream from anything
  • 62. MediaBrowserService …or how to expose your media to the rest of the ecosystem
  • 63. MediaBrowserService …or how to expose your media to the rest of the ecosystem #ecosystem
  • 70. AudioTrack … The lower level MediaPlayer
  • 71. AudioTrack API < 26 AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, // most likely 44.1 Khz AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, numberOfSamples, AudioTrack.MODE_STATIC)
  • 73. AudioTrack usage fun play() { val audioTrack = initAudioTrack() val someSoundDataInByteArray = getSoundDataSomewhere() audioTrack.write(someSoundsInByteArray, startOffset, bufferSize) }
  • 75. AudioRecord … The lower level MediaRecorder
  • 78. Build-in Effects • Equalizer • Virtualizer • BassBoost • PresetReverb • EnvironmentalReverb
  • 79. Effect Usage val reverb = PresetReverb(priority, audioSession).apply { preset = PresetReverb.PRESET_LARGEHALL enabled = true ... } audioTrack.apply { attachAuxEffect(reverb.id) setAuxEffectSendLevel(1.0F) ... }
  • 83. Last but not least
  • 84. Last but not least
  • 85. How does it work
  • 86. How does it work Controller
  • 87. How does it work Controller Interface
  • 88. How does it work Controller Computer Interface
  • 89. How does it work Controller Computer Controller Interface
  • 90. How does it work Controller Computer Controller Interface Controller
  • 91. How does it work Controller Computer Controller Interface Controller
  • 94. Good Reads • Understanding MediaSession http://bit.ly/mediasession • Building a Video Player app in Android http://bit.ly/ vplayerandroid • ADB Podcast Episode 85 Focus on Audio http://bit.ly/ adbaudiofocus • Styling Android’s MIDI posts http://bit.ly/midiandroid