336 lines
16 KiB
HTML
336 lines
16 KiB
HTML
|
<!doctype html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="utf-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||
|
|
||
|
<title>Apollon App</title>
|
||
|
<link rel='shortcut icon' href='https://framecca.github.io/Apollon/img/Apollon.png' type='image/x-icon' />
|
||
|
|
||
|
<link rel="stylesheet" href="css/reset.css">
|
||
|
<link rel="stylesheet" href="css/reveal.css">
|
||
|
<link rel="stylesheet" href="css/theme/Apollon.css">
|
||
|
|
||
|
<!-- Theme used for syntax highlighting of code -->
|
||
|
<link rel="stylesheet" href="lib/css/monokai.css">
|
||
|
|
||
|
<!-- Printing and PDF exports -->
|
||
|
</head>
|
||
|
<body>
|
||
|
<style>
|
||
|
small {
|
||
|
font-size: 5px;
|
||
|
}
|
||
|
</style>
|
||
|
<div class="reveal">
|
||
|
<div class="slides">
|
||
|
<section>
|
||
|
<img src = "img/logo.png">
|
||
|
<p style = "color: #e5c100">Borello Nazareno - Galatola Marco - Mecca Francesco</p>
|
||
|
</section>
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Cos'è Apollon?
|
||
|
Un'applicazione che permette lo streaming e l'organizzazione della propria libreria musicale da PC a dispositivi Android
|
||
|
|
||
|
Si divide in due parti, un client Android, sul quale si concentra la presentazione, ed un server PC, entrambi sviluppati in Kotlin
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Caratteristiche principali
|
||
|
* Streaming in tre preset di qualità
|
||
|
* Multiutente
|
||
|
* Gestione playlist personalizzate
|
||
|
* Possibilità di eseguire ricerche sulla propria libreria
|
||
|
* Notifiche interattive
|
||
|
* Supporto completo per quattro lingue: Inglese, Francese, Italiano e Swahili
|
||
|
* Layout del player alternativo per schermi più lunghi
|
||
|
* Condivisione tramite app esterne del brano in ascolto
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
<img class="left_img" src="img\ApolloCensored.png">
|
||
|
<br>
|
||
|
<h2>Perché Apollon?</h2>
|
||
|
Il nome omaggia Apollo, dio greco della musica e della poesia, mentre il logo rappresenta la lira tipicamente associata alla divinità
|
||
|
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Confronto con Spotify ed Apple Music
|
||
|
| | <img src="img\Spot.png"> | <img src="img/am2.jpg"> | <img src="img\Apollon.png"> |
|
||
|
|:---------------------:|:------------------------:|:----------------------:|:---------------------------:|
|
||
|
| **Qualità** (kbps) | [128/256](https://support.spotify.com/us/article/high-quality-streaming/) | [≤256](https://www.theverge.com/2019/8/7/20758633/apple-digital-masters-itunes-rebrand-music-quality) |[160, 256, 500](https://wiki.audacityteam.org/wiki/OGG)|
|
||
|
| **Censura** | Sì | Sì | No |
|
||
|
| **Gestione catalogo** | Azienda | Azienda | Utente |
|
||
|
| **DRM** | Sì | Sì | No |
|
||
|
| **Costo** | Ads/Fee | Fee | Open Source |
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Il nostro target di utenti
|
||
|
Apollon si rivolge a quegli appassionati di musica
|
||
|
che non vogliono rinunciare alla propria collezione anche lontano da casa
|
||
|
|
||
|
Il backend si basa su MPD, un software Linux ampiamente diffuso come riproduttore fra
|
||
|
la comunità di audiofili
|
||
|
</textarea>
|
||
|
</section>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
<h3>Come un media player tradizionale</h3>
|
||
|
<img src="img\player.png" class="left_img small_img">
|
||
|
<br><br>
|
||
|
Vengono offerte tutte le funzionalità di un media player tradizionale:
|
||
|
<ul>
|
||
|
<li>Play/Pause</li>
|
||
|
<li> Skip</li>
|
||
|
<li> Loop</li>
|
||
|
<li> Riproduzione casuale</li>
|
||
|
<li> Seek</li>
|
||
|
<li> Riproduzione in background</li>
|
||
|
</ul>
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Schema media player
|
||
|
<br>
|
||
|
<img class="big_img" src="img\playerArch.png">
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h4>Audio manager e Audio focus</h4>
|
||
|
<p>AudioManager ci permette di gestire l'interazione con gli eventi esterni all'applicazione, come notifiche, chiamate, gestione del volume.</p>
|
||
|
<script src="https://gist.github.com/FraMecca/11c3dd5b8f20cfb52c5620c9f9ad9262.js"></script>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Sfondo e Notifiche
|
||
|
<img src="img\notification.png" class="left_img small_img">
|
||
|
<br><br>
|
||
|
Quando un brano è in riproduzione viene generata una notifica interattiva contenente i metadati rilevanti
|
||
|
Inoltre l'immagine associata viene impostata come sfondo della schermata di blocco
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h4>Implementazione di sfondo e notifiche</h4>
|
||
|
<script src="https://gist.github.com/FraMecca/a1855beac5cee1e1fa1e83e489317898.js"></script>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Miniplayer
|
||
|
<img src="img\miniplayer.png" class="left_img small_img">
|
||
|
<br><br>
|
||
|
Il miniplayer permette un controllo basilare sulla riproduzione mentre si naviga l'applicazione
|
||
|
<br><br>
|
||
|
Al tocco si viene riportati al player esteso
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section >
|
||
|
<h2>Ottimizzazione</h2>
|
||
|
<p>Le risorse vengono liberate quando il player rimane inutilizzato per tre minuti</p>
|
||
|
<script src="https://gist.github.com/FraMecca/0395c9f879e0d399f6cfbc40b1921833.js"></script>
|
||
|
</section>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Oltre un media player tradizionale
|
||
|
Vengono offerte alcune funzionalità aggiuntive oltre a quelle descritte in precedenza:
|
||
|
* Testo della canzone
|
||
|
* Supporto per le gesture
|
||
|
* Multilingua
|
||
|
* UI alternativa
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Lyrics
|
||
|
<img src="img\lyrics.png" class="left_img small_img">
|
||
|
<br>
|
||
|
<br>
|
||
|
Ottenute dal server da ChartLyrics, convertite in JSON ed inviate al client
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Gestures
|
||
|
<img src="gifs\favourite.gif" class="ros_img" style="margin-right:160px"><img src="gifs\swipe.gif" class="ros_img">
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h4>Implementazione delle Gestures</h4>
|
||
|
<script src="https://gist.github.com/FraMecca/2970cc4b600a6ebb2559fc26136062b6.js"></script>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Multilingua
|
||
|
* supporto per quattro lingue: Italiano (it_IT), Francese (fr_FR), Inglese (en_US) e Swahili (sw_UG)
|
||
|
* ottenuto tramite `Locale resource-resolution` (api >=24)
|
||
|
* Un file string.xml per ogni lingua supportata
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Layout player alternativo
|
||
|
<img class="small_img" src="img\player.png" style="margin-right=20px"><img class="small_img" src="img\player_long.png">
|
||
|
</textarea>
|
||
|
</section>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Architettura Client Server
|
||
|
<img class="big_img" src="img\s_arch.png">
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Comunicare col server
|
||
|
La comunicazione avviene tramite un Singleton che espone funzioni gestite da AsyncTask e mantiene una cache
|
||
|
dei risultati ricevuti
|
||
|
<br><br>
|
||
|
Ad ogni AsyncTask è assegnato un TaskListener, chiamato asincronicamente ad operazione conclusa,
|
||
|
il quale riceve un TaskResult (specifico per l'operazione) atto a modellare il risultato richiesto
|
||
|
<br><br>
|
||
|
Questo sistema fa sì che le operazioni di backend non blocchino la UI, preservando il più possibile l'interattività
|
||
|
con l'utente
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h3>AsyncTask</h3>
|
||
|
<script src="https://gist.github.com/FraMecca/e599908de37fd071668635dc93bc9d3c.js"></script>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h3>TaskListener, TaskResult e Server singleton</h3>
|
||
|
<script src="https://gist.github.com/FraMecca/d81657262e0e9f5183d06e2804b03672.js"></script>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Complicazioni sul seeking
|
||
|
Non sempre è possibile fare seeking su un brano poiché la classe
|
||
|
MediaPlayer implementa la gestione di streaming via HTTP mentre il server utilizza il transcoding on the fly
|
||
|
<br><br>
|
||
|
Questo fa sì che la dimensione effettiva del file muti nel tempo e perciò non possa essere nota a priori,
|
||
|
per risolvere il problema si adotta una soluzione in due step:
|
||
|
* Controllare lo stato del buffer
|
||
|
* Se il buffer non è sufficiente, fare una richiesta `HTTP Content-Range`
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section>
|
||
|
<h2>Implementazione seek</h2>
|
||
|
<script src="https://gist.github.com/FraMecca/5e631d8910e446eef1e2336dc6a818d5.js"></script>
|
||
|
</section>
|
||
|
</section>
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Visualizzazione
|
||
|
La parte di visualizzazione ha richiesto l'uso di varie componenti:
|
||
|
* **Fragments** per mantenere il binding tra Activity e Service
|
||
|
* **Adapter** per visualizzare liste modulari di elementi personalizzati tramite **Card**
|
||
|
* **Picasso** per gestire immagini remote
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Fragment
|
||
|
Ogni schermata è gestita da un fragment specifico invocato dall'Activity
|
||
|
- I fragment sono inseriti in uno stack per permettere all'utente di tornare alle schermate precedenti
|
||
|
- Il nostro target di utenti ha un catalogo musicale di vaste dimensioni: per questo motivo è buona pratica utilizzare la classe [RecyclerView](https://developer.android.com/guide/topics/ui/layout/recyclerview).
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Adapter e Card
|
||
|
<img class="left_img small_img" src="img\albums.png">
|
||
|
<img class="left_img small_img" src="img\songs.png">
|
||
|
<br><br>
|
||
|
Adatper e Card gestiscono l'interfaccia dei fragment composti da liste di album o canzoni
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section >
|
||
|
<h2>Picasso</h2>
|
||
|
<p>
|
||
|
Il download ed il caching delle immagini prese dalla rete, come cover-art ed artisti, avviene utilizzando
|
||
|
la libreria <a><href="https://square.github.io/picasso/">Picasso</href></a>
|
||
|
</p>
|
||
|
<script src="https://gist.github.com/FraMecca/d95d00ea80ff5ed6b63e20878c7c8656.js"></script>
|
||
|
</section>
|
||
|
</section>
|
||
|
<section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
### Usare Kotlin per lo sviluppo
|
||
|
Kotlin ci ha permesso di usare con più facilità vari pattern architetturali e tecniche di programmazione funzionale.
|
||
|
|
||
|
* Singleton: gestione della comunicazione col server
|
||
|
* Companion Object: a cui viene delegata l'inizializzazione dei fragments
|
||
|
* Sum Types: parametrizzazione dei fragments
|
||
|
* Pattern Matching: semplifica la logica e la struttura del codice
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section >
|
||
|
<h4>Pattern matching e sealed classes</h4>
|
||
|
<script src="https://gist.github.com/FraMecca/a615a249cbf85f60fb1e9399a1bc88c8.js"></script>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## Backend
|
||
|
Apollon comunica con un backend, scritto in Kotlin, installato sul server dell'utente.
|
||
|
Il backend si occupa di:
|
||
|
- leggere il database musicale di [MPD](https://en.wikipedia.org/wiki/Music_Player_Daemon)
|
||
|
- convertire i brani musicali richiesti e leggere i metadati
|
||
|
- comunicare attraverso un'api REST-like
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section data-markdown>
|
||
|
<textarea data-template>
|
||
|
## API
|
||
|
Quattro aree funzionali
|
||
|
- Libreria: navigazione per album, genere, artista e ricerca
|
||
|
- Playlists: creazione e modifica di playlist specifiche per ogni utente
|
||
|
- Streaming: gestione del flusso di dati, qualita` dello stream, avanzamento, signaling delle risorse in uso
|
||
|
- Handle per operazioni sui singoli oggetti del catalogo: artista, album, genere, brano, metadati
|
||
|
</textarea>
|
||
|
</section>
|
||
|
<section >
|
||
|
<p>
|
||
|
Come nell'app, vengono utilizzati pattern architetturali tipici della programmazione ad oggetti e funzionale.
|
||
|
La logica del backend è codificata nei tipi <em>Response</em> e <em>Request</em> che tracciano il bordo dell'API.
|
||
|
</p>
|
||
|
<script src="https://gist.github.com/FraMecca/7350f897349834942ed8a7dd2b81ca0a.js"></script>
|
||
|
</section>
|
||
|
</section>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<script src="js/reveal.js"></script>
|
||
|
|
||
|
<script>
|
||
|
Reveal.initialize({
|
||
|
hash: true,
|
||
|
dependencies: [
|
||
|
{ src: 'plugin/markdown/marked.js' },
|
||
|
{ src: 'plugin/markdown/markdown.js' },
|
||
|
{ src: 'plugin/highlight/highlight.js' },
|
||
|
{ src: 'plugin/notes/notes.js', async: true }
|
||
|
]
|
||
|
});
|
||
|
</script>
|
||
|
</body>
|
||
|
</html>
|