A Java application/library implementation of the DMAP family (DAAP, DACP, DPAP) and RAOP with Guice + Jetty + Zeroconf/Bonojur (through jmDNS). The functionality is planned to resemble what is provided by eg. dmapd. It should however be thought of as an integration library, not a final application itself. jolivia is scoped to support the following proprietary protocols:
- Digital Media Access Protocol (DMAP)
- Digital Audio Access Protocol (DAAP)
- Digital Photo Access Protocol (DPAP)
- Digital Media Control Protocol (DMCP)
- Digital Audio Control Protocol (DACP)
- Remote Audio Output Protocol (RAOP)
- run jolivia
your_password
must be provided from https://support.google.com/accounts/answer/185833android_id
is IMEI/MEID/ESN (but anything might be ok)
$ Java -cp ... org.dyndns.jkiddo.JoliviaMainer [email protected] your_password android_id
- select remote library on Music.app (library name is set by
name()
method)
new Jolivia.JoliviaBuilder().name("Google Play Music Library")
- enter pairing code (code is set by
pairingCode()
method)
.port(4000).pairingCode(2337).musicStoreReader(reader)
I'll just give you a brief introduction to how the DACP protocol works (you can read more on http://jsharkey.org/blog/2009/06/21/itunes-dacp-pairing-hash-is-broken/, http://dacp.jsharkey.org/, http://jinxidoru.blogspot.dk/2009/06/itunes-remote-pairing-code.html and http://www.awilco.net/doku/dacp).
- The client side of DACP announces itself through Bonjour. This is done by Jolivia
- The announcement is 'caught/read' by iTunes. At this point you should be able to see the 'like to pair?'-button in iTunes
- iTunes makes a request to the webservice that the client is required to implement. This service is implemented by Jolivia.
- The service responds with a OK/NotOK if the correct pairing code is submitted and a negotiation key is stored in both Jolivia and iTunes. This is implemented by Jolivia.
- iTunes announces itself through Bonjour as paired.
- Joliva detects the iTunes announcement. If the iTunes library/user is detected as a paired iTunes, Jolivia initiates a session and calls the registered ClientSessionListener that is registered in the constuctor of Jolivia.
The session is your 'remote control' instance. On a session you can do the remote control stuff or eg. traverse the library. See the following code example:
@Test
public void usage() throws Exception {
// As soon as you have entered the pairing code '1337' in iTunes the
// registerNewSession will be invoked and the pairing will be stored in
// a local db file and in iTunes as well. Clear the pairing in iTunes by
// clearing all remotes in iTunes as usual. Clear the pairing in Jolivia
// by deleting the db
// file. Once paired every time you start iTunes this method will be
// called. Every time the iTunes instance is
// closed the tearDownSession will be invoked.
new Jolivia.JoliviaBuilder().clientSessionListener(new IClientSessionListener() {
private Session session;
@Override
public void tearDownSession(String server, int port) {
// Maybe do some clean up?
try {
session.logout();
} catch(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@SuppressWarnings("unused")
@Override
public void registerNewSession(Session session) throws Exception {
// Showcase on some actions you can do on a session ...
// ////////////////////////////////////////
this.session = session;
// getUpdateBlocking blocks until an event happens in iTunes -
// eg. pressing play, pause, etc. ...
UpdateResponse response = this.session.getUpdateBlocking();
Database itunesDatabase = this.session.getDatabase();
// Get all playlists. For now the playlists only contains the
// master playlist. This is to be expanded
Collection<Container> playlists = itunesDatabase.getContainers();
// Traverse the library for eg. all tracks
for(SongArtist artist : this.session.getLibrary().getAllArtists().getBrowseArtistListing().getSongArtists()) {
System.out.println(artist.getValue());
}
long itemId = 0;
// Extract information from a generic listing
for(ListingItem item : this.session.getLibrary().getAllTracks().getListing().getListingItems()) {
System.out.println(item.getSpecificChunk(SongAlbum.class).getValue());
System.out.println(item.getSpecificChunk(SongArtist.class).getValue());
System.out.println(item.getSpecificChunk(SongTime.class).getValue());
System.out.println(item.getSpecificChunk(SongTrackNumber.class).getValue());
System.out.println(item.getSpecificChunk(SongUserRating.class).getValue());
System.out.println(item.getSpecificChunk(ItemName.class).getValue());
System.out.println(item.getSpecificChunk(ItemKind.class).getValue());
System.out.println(item.getSpecificChunk(ItemId.class).getValue());
itemId = item.getSpecificChunk(ItemId.class).getValue();
}
// Showcase on some actions you can do on speakers ...
// ////////////////////////////////////////
RemoteControl remoteControl = this.session.getRemoteControl();
// Set min volume
remoteControl.setVolume(0);
// Set max volume
remoteControl.setVolume(100);
remoteControl.setVolume(0);
// Get the master volume
remoteControl.getMasterVolume();
// Get all speakers visible to iTunes instance
Collection<Speaker> speakers = remoteControl.getSpeakers();
// Mark all speakers active meaning they are prepared for being
// used for the iTunes instance
for(Speaker s : speakers) {
s.setActive(true);
}
// Assign all the active speakers to the iTunes instance. This
// means that all the speakers will now be used for output
remoteControl.setSpeakers(speakers);
// Change the volume individually on each speaker
speakers = remoteControl.getSpeakers();
for(Speaker s : speakers) {
remoteControl.setSpeakerVolume(s.getId(), 60, 50, 40, 30, 100);
}
session.getLibrary().getAlbumArtwork(itemId, 320, 320);
session.getRemoteControl().fetchCover(320, 320);
}
}).build();
}
- DAAP share as provided by iTunes including Zeroconf service discovery/publication.
- DPAP share as provided by iPhoto including Zeroconf service discovery/publication.
- DACP pairing and remote control functions. Jolivia implements serverside and clientside, meaning that you can use Jolivia for remote control but you can also use eg. Apple Remote against it.
- RAOP Streaming aka. Airport Express emulation.
- RAOP client - could be implemented as in RPlay, AirReceiver, AP4J-Player, qtunes or JAirPort.
- DLNA/DMAP Gateway translation.
This project has found great inspiration in many projects and the people behind them, among those are the following:
- TunesRemote+
- TunesRemote SE
- jems - Java Extensible Media Server
- ytrack
- RPlay
- AirReceiver
- AP4J-Player
- JAirPort
- rkapsi/daap
- qtunes
- dmap-parser
This project is licensed under the license presented in the license.txt file. Anyone who uses Jolivia in any kind of software - being commercial or not must notify the author and submit a comment on this project site stating its usage and purpose.
Copyright 2013 Jens Kristian Villadsen.