Lo streaming musicale è una pratica sempre più comune.
Un numero sempre maggiore di persone si iscrive a servizi come Spotify e Apple Music per poter ascoltare i propri artisti preferiti in qualunque situazione.
Questi servizi sono in genere supportati da abbonamenti o pubblicità.
Queste piattaforme, nonostante abbiano raggiunto una grande diffusione, sono molto criticate dagli appassionati, dai critici di musica e dagli artisti stessi.
Le critiche più diffuse sono le seguenti:
* bassissima qualità di riproduzione: i file audio inviati in streaming da Spotify sono in formato mp3 128kpbs, 192kbps per gli utenti premium. Inoltre Spotify [mente sull'encoding dei dati inviati](https://community.spotify.com/t5/iOS-iPhone-iPad/Spotify-Premium-sound-quality-issues-320-kbps-quot-equivalent/td-p/857381).
* censura: entrambe le piattaforme praticano la censura, sia a [fini](https://www.theverge.com/2019/4/12/18305087/congress-apple-criticism-china-communist-tiananmen-pro-democracy) [politici](https://www.breitbart.com/tech/2015/11/13/spotifys-political-censorship-should-worry-us-all/) che per motivi [puritani](https://www.reddit.com/r/spotify/comments/1znw32/why_the_fuck_are_all_the_songs_getting_censored/), non permettendo agli utenti di disabilitare il filtro per la [censura](https://discussions.apple.com/thread/7105598).
* Catalogazione imprecisa: Spotify ed Apple Music offrono nella maggior parte dei casi una sola versione di ogni disco. Inoltre se l'utente carica un mastering differente di un brano già esistente nel loro database, lo scartano.
* Assenza di artisti di nicchia: i database di queste due grandi piattaforme, oltre ad essere prive di tutta la musica non distribuita da etichette riconosciute, offrono uno scarso catalogo per generi meno [mainstream](https://www.hypebot.com/hypebot/2018/05/why-spotify-may-actually-kill-jazz-soul.html). Ne sono un'esempio i brani di musica classica, che [sono solo l'1% del totale](https://news.allaboutjazz.com/how-spotifys-continued-expansion-is-killing-niche-music-genres).
* Pubblicazioni di falsi dati per motivi di PR: [Spotify ha mentito in varie occasioni riguardo al suo catalogo](https://www.theguardian.com/technology/2017/jul/13/are-spotifys-fake-artists-any-good).
* DRM: il Digital Rights Management è una tecnologia che limita le possibilità di riproduzione del file su dispositivi non autorizzati
* Mancata retribuzione agli artisti: Spotify ed Apple Music obbligano gli artisti a fare contratti con delle case discografiche per poter essere pubblicati nella loro piattaforma. Inoltre i compensi finali sono estramemente limitati e per questo molti artisti [rifiutano](https://time.com/3554468/why-taylor-swift-spotify/) di pubblicare la [loro](https://www.theguardian.com/technology/2013/jul/29/spotify-vs-musicians-streaming-royalties) [musica](https://www.bbc.com/news/newsbeat-43240886).
La nostra app si propone come un'alternativa per appassionati di musica e collezionisti, che non vogliono rinunciare allo streaming seppur continuando ad usufruire della propria collezione musicale di brani di nicchia ed in alta definizione, scaricati da piattaforme come Bandcamp o "rippati" dai CD audio.
Il nome, Apollon, è un omaggio alla divinità greca del sole e della musica.
# Specifiche generali dell'applicazione
L'applicazione avrà come funzionalità principale quella di riprodurre la collezione musicale personale di ogni singolo utente.
Lo streaming è permesso in tre preset di qualità, alto, medio e basso.
L'applicazione offre funzionalità di ricerca e la possibilità di creare playlists.
L'app all'avvio si connetterà ad un server, programmato con le stesse tecnologie e pattern dell'applicazione, gestito da ogni utente. Una spiegazione più ampia del server è offerta in appendice. Basti notare che il server offre la possibilità di gestire più utenti, autenticati tramite nickname e password.
# Alternative su play store
Oltre alle piattaforme come Spotify e Apple Music che offrono lo streaming musicale ma con gli svantaggi di cui sopra,
vi sono solamente due alternative per chi vuole usufruire dello streaming della propria collezione musicale.
La prima è subsonic, supportato da [varie](https://f-droid.org/en/packages/org.moire.ultrasonic/) [applicazioni](https://play.google.com/store/apps/details?id=net.sourceforge.subsonic.androidapp) ma che non supporta il database più diffuso in ambito audiofilo di [mpd](https://www.musicpd.org/) e non permette di fare seek della traccia audio.
La seconda alternativa è il già citato mpd, che offre una funzione di streaming originariamente pensato per le webradio. [Vi](https://f-droid.org/en/packages/com.namelessdev.mpdroid) [sono](https://f-droid.org/en/packages/org.gateshipone.malp) [app](https://play.google.com/store/apps/details?id=net.prezz.mpr) che supportano un buon numero di features per mpd ma non permettono di creare playlists o di gestire più utenti. La maggiore limitazione di mpd è che permette lo streaming di un solo brano alla volta qualsiasi sia il numero di ascoltatori.
# Benefici dell'applicazione
La comunità di audiofili con un particolare interesse per le tecnologie ha deciso da anni che lo standard per i sistemi di riproduzione di musica digitali sono costituiti da sistemi Linux con kernel real time e MPD come riproduttore.
La nostra applicazione ha come interesse primario quello di attrarre questa comunità permettendo da una parte l'integrazione con le tecnologie già in uso (MPD e Linux), dall'altra ampio margine di controllo sulla riproduzione dei file e la gestione della libreria.
Gli utenti possono condividere la loro vasta libreria musicale con più utenti e fare streaming dei propri file audio in diversi formati in base alle esigenze e alla banda disponibile.
Il catalogo musicale è nel pieno controllo dell'utente che andrà a gestirlo con gli strumenti che già utilizzava.
Il server con il quale l'applicazione comunica supporta la lettura dei metadati dei file e del database di MPD.
All'avvio l'applicazione richiedere l'inserimento delle credenziali di accesso al server (ip, porta, username, password) da parte dell'utente. Tali credenziali vengono memorizzate per poter essere riutilizzate al prossimo avvio.
Una volta effettuato il login si potrà navigare la libreria musicale.
La navigazione è gestita da un Fragment parametrizzato dalla modalità scelta per la navigazione, ossia genere, artista o album.
La navigazione è arricchita dalla visualizzazione delle copertine e delle foto degli artisti, scaricate interattivamente.
Una volta selezionata una canzone questa verrà messa in riproduzione. Dal Fragment è possibile selezionare la qualità di riproduzione, ovvero High Quality, Medium Quality e Low Quality. Inoltre, nel caso si stesse ascoltando una canzone, è possibile visualizzare le lyrics.
Durante l'ascolto è possibile aggiungere il brano in riproduzione alla playlist "Favourites".
Le altre playlists sono visualizzabili attraverso le schermate di navigazione e possono essere modificate tramite apposito menù.
Infine è possibile condividere la canzone in ascolto attraverso il bottone "condividi" inviando un messaggio di testo.
## Scelte tecniche
### Riproduzione in streaming
La riproduzione in streaming presenta notevoli difficoltà se abbinata al transcoding on the fly, ovvero la riduzione di qualità di un brano in alta definizione mentre lo si sta ascoltando. La riproduzione di un sorgente tramite protocllo HTTP è fornita dalla classe MediaPlayer del framework Android. Durante la riproduzione la dimensione del file è in continua crescita poiché la dimensione del file sul server è proporzionale alla percentuale di file del quale è già stato compiuto il transcoding. Inoltre il transcoding effettuato tramite Variabile Bit Rate per definizione non permette di conoscere la dimensione finale del file. Per permettere all'utente di fare seek della traccia audio, Apollon interroga la classe MediaPlayer sulla quantità di buffer disponibile e interroga il server sullo stato del transcoding. Attraverso queste due informazioni Apollon effettua il seek con precisione. Quando il seek non è disponibile per mancanza di buffer, la barra di riproduzione viene leggermente oscurata.
### Interazione col dispositivo
Quando un brano è in riproduzione viene mostrata la copertina come wallpaper del blocco schermo.
Inoltre la riproduzione si ferma se vengono staccate le cuffie o se arriva una chiamata.
L'output di Apollon viene ridotto per qualche istante nel caso sopraggiunga una notifica.
### Servizi di terze parti
Le lyrics vengono fornite da ChartLyrics tramite api web in formato XML.
Le immagini sono fornite da WikiData e scaricate attraverso la libreria Picasso che si occupa di fare caching talora necessario.
### Pattern architetturali
Nel codice risalta un notevole utilizzo di pattern architetturali, alcuni comuni a Java e Kotlin, altri specifici di Kotlin e della programmazione funzionale. Inoltre abbiamo seguito differenti tecniche di programmazione e riuso specifici del framework Android.
All'interno dei pattern tipici della programmazione ad oggetti compaiono:
* Adapters: usato per adattare l'interfaccia di una classe ad un'altra. Nel nostro caso è stato usato questo pattern per le classi che forniscono la logica e la visualizzazione all'interno dei fragments.
* Builder: pattern creazionale utilizzato per l'instanziazione step by step di oggetti complessi. Fra le varie classi in cui usiamo questo pattern, la più importante sono quelle per la gestione dei metadati del brano in riproduzione e per l'instanziazione del mediaplayer.
* Events: gli eventi sono oggetti instanziati in risposta a degli input esterni (quali rete o utente) e vengono gestiti in maniera asincrona da differenti funzioni. Vengono utilizzati nella nostra applicazione per gestire la UI e gli eventi di rete relativi lla riproduzione in streaming.
Kotlin ci ha permesso da un lato di usare con più facilità e in maniera meno verbosa dei pattern tipi della programmazione ad oggetti, in particolare:
* Singleton: pattern che restringe l'instanziazione di una classe ad un solo oggetto. Utilizzata per la connessione al server e la gestione delle credenziali (che a sua volta è un adapter per SharedPreferences).
* Companion Object: un singleton che ha accesso ai membri privati degli oggetti instanziati dalla classe compagno (ovvero della classe all'interno del quale è dichiarato). Ne facciamo uso per la creazione delle instanze dei fragments.
* Sum Types: pattern tipicamente funzionale in cui una struttura dati può contenere diversi tipi predefiniti. Abbiamo modellato i sum types in Kotlin attraverso l'uso delle **sealed class** che ci ha permesso di codificare lo stato del programma attraverso i tipi.
* Pattern Matching: pattern estremamente correlato all'uso dei sum types. Attraverso il pattern matching siamo sicuri che in ogni branch del nostro codice abbiamo preso in considerazione ogni stato possibile. L'uso di assert(false) ci permette di asserire quali tipi non devono raggiungere quella sezione di codice.
Infine nella nostra codebase abbiamo fatto un uso estensivo delle componenti del framework Android, in particolare:
* Fragments: componenti che incapsulano il comportamente e l'UI di una singola activity. Ci ha permesso di riciclare della logica complessa e adattare le componenti grafiche a diversi layout.
* Services e AsyncTasks: per fare in modo che il thread principale non si blocchi abbiamo utilizzato dei background service. In particolare ogni operazione bloccante è incapsulata dentro un AsyncTask che ne modella il comportamento in base al risultato.