private async Task <ConnectionResult> LoginAsync() { DacpRequest request = new DacpRequest("/login"); request.QueryParameters["pairing-guid"] = "0x" + PairingCode; request.IncludeSessionID = false; try { var response = await SendRequestAsync(request).ConfigureAwait(false); // Process response var nodes = DacpNodeDictionary.Parse(response.Nodes); if (!nodes.ContainsKey("mlid")) { return(ConnectionResult.InvalidPIN); } SessionID = nodes.GetInt("mlid"); UpdateNowPlayingAlbumArtUri(); } catch (DacpRequestException e) { int statusCode = (int)e.Response.StatusCode; if (statusCode >= 500 && statusCode <= 599) { return(ConnectionResult.InvalidPIN); } return(ConnectionResult.ConnectionError); } catch { return(ConnectionResult.ConnectionError); } return(ConnectionResult.Success); }
internal Task <bool> SetPropertyAsync(string propertyName, string value) { DacpRequest request = new DacpRequest("/ctrl-int/1/setproperty"); request.QueryParameters[propertyName] = value; return(SendCommandAsync(request)); }
internal async Task <DacpResponse> SendRequestAsync(DacpRequest request) { if (request.IncludeSessionID) { request.QueryParameters["session-id"] = SessionID.ToString(); } return(await SendRequestAsync(request.GetURI(), request.CancellationToken).ConfigureAwait(false)); }
internal async Task <bool> SendCommandAsync(DacpRequest request) { try { await SendRequestAsync(request).ConfigureAwait(false); } catch { return(false); } return(true); }
public async Task <bool> DisableAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/setspeakers"); request.QueryParameters["speaker-id"] = string.Join(",", Client.Speakers.Where(s => s.IsActive && s != this).Select(s => "0x" + s.ID.ToString("x"))); try { await Client.SendRequestAsync(request).ConfigureAwait(false); } catch { return(false); } return(true); }
public async Task <bool> EnableSingleAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/setspeakers"); request.QueryParameters["speaker-id"] = "0x" + ID.ToString("x"); try { await Client.SendRequestAsync(request).ConfigureAwait(false); } catch { return(false); } return(true); }
public Task <bool> SendPreviousTrackCommandAsync() { // If the track doesn't change, we won't receive a play status update int totalMS = (int)CurrentTrackDuration.TotalMilliseconds; UpdateTrackTime(totalMS, totalMS); DacpRequest request = new DacpRequest("/ctrl-int/1/previtem"); return(SendCommandAsync(request)); }
internal async Task <IDacpList> GetAlphaGroupedListAsync <T>(DacpRequest request, Func <byte[], T> itemGenerator, string listKey = DacpUtility.DefaultListKey) { try { var response = await SendRequestAsync(request).ConfigureAwait(false); return(DacpUtility.GetAlphaGroupedDacpList(response.Nodes, itemGenerator, listKey)); } catch (Exception) { return(new DacpList <T>(false)); } }
internal async Task <List <T> > GetListAsync <T>(DacpRequest request, Func <DacpNodeDictionary, T> itemGenerator, string listKey = DacpUtility.DefaultListKey) { try { var response = await SendRequestAsync(request).ConfigureAwait(false); return(DacpUtility.GetItemsFromNodes(response.Nodes, itemGenerator, listKey).ToList()); } catch (Exception) { return(new List <T>()); } }
public Task <bool> SendGeniusShuffleCommandAsync() { if (!ServerSupportsGeniusShuffle) { return(Task.FromResult(false)); } DacpRequest request = new DacpRequest("/ctrl-int/1/genius-shuffle"); // Apple's Remote seems to always set "span" to "$Q" request.QueryParameters["span"] = "$Q"; return(SendCommandAsync(request)); }
public Task <bool> SendiTunesRadioNeverPlayThisSongCommandAsync() { if (!IsPlayingiTunesRadio) { return(Task.FromResult(false)); } DacpRequest request = new DacpRequest("/ctrl-int/1/setproperty"); request.QueryParameters["com.apple.itunes.liked-state"] = "3"; request.QueryParameters["database-spec"] = DacpQueryPredicate.Is("dmap.itemid", "0x" + CurrentDatabaseID.ToString("x")).ToString(); request.QueryParameters["item-spec"] = DacpQueryPredicate.Is("dmap.itemid", "0x" + CurrentItemID.ToString("x")).ToString(); return(SendCommandAsync(request)); }
private async Task <bool> GetSpeakersAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/getspeakers"); try { var response = await SendRequestAsync(request).ConfigureAwait(false); var speakerNodes = response.Nodes.Where(n => n.Key == "mdcl").Select(n => DacpNodeDictionary.Parse(n.Value)).ToList(); var speakers = Speakers; // Determine whether we need to replace the list of speakers bool replaceSpeakers = false; if (speakers == null || speakers.Count != speakerNodes.Count) { replaceSpeakers = true; } else { // Determine whether we still have the same speaker IDs for (int i = 0; i < speakers.Count; i++) { if (speakers[i].ID != (UInt64)speakerNodes[i].GetLong("msma")) { replaceSpeakers = true; break; } } } // Create the new list of speakers or update the existing speakers if (replaceSpeakers) { Speakers = speakerNodes.Select(n => new AirPlaySpeaker(this, n)).ToList(); } else { for (int i = 0; i < speakers.Count; i++) { speakers[i].ProcessNodes(speakerNodes[i]); } } } catch { return(false); } return(true); }
private async Task <bool> GetVolumeLevelAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/getproperty"); request.QueryParameters["properties"] = "dmcp.volume"; try { var response = await SendRequestAsync(request).ConfigureAwait(false); var nodes = DacpNodeDictionary.Parse(response.Nodes); CurrentVolumeLevel = nodes.GetInt("cmvo"); } catch { return(false); } return(true); }
private async Task <bool> SetVolumeLevelAsync(int value, bool replaceMasterVolume) { DacpRequest request = new DacpRequest("/ctrl-int/1/setproperty"); request.QueryParameters["dmcp.volume"] = value.ToString(); if (replaceMasterVolume) { request.QueryParameters["include-speaker-id"] = ID.ToString(); } else { request.QueryParameters["speaker-id"] = ID.ToString(); } try { await Client.SendRequestAsync(request).ConfigureAwait(false); } catch { return(false); } return(true); }
private async Task <bool> GetTrackTimePositionAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/getproperty"); request.QueryParameters["properties"] = "dacp.playingtime"; try { var response = await SendRequestAsync(request).ConfigureAwait(false); var nodes = DacpNodeDictionary.Parse(response.Nodes); int totalMS = nodes.GetInt("cast"); int?remainingMS = nodes.GetNullableInt("cant"); UpdateTrackTime(totalMS, remainingMS); } catch { return(false); } return(true); }
private async Task <bool> GetLibraryUpdateAsync(CancellationToken cancellationToken) { DacpRequest request = new DacpRequest("/update"); request.QueryParameters["revision-number"] = CurrentLibraryUpdateNumber.ToString(); request.QueryParameters["daap-no-disconnect"] = "1"; try { var response = await SendRequestAsync(request).ConfigureAwait(false); if (cancellationToken.IsCancellationRequested) { return(false); } var nodes = DacpNodeDictionary.Parse(response.Nodes); CurrentLibraryUpdateNumber = nodes.GetInt("musr"); } catch { return(false); } return(true); }
private async Task <bool> GetServerCapabilitiesAsync() { DacpRequest request = new DacpRequest("/ctrl-int"); request.IncludeSessionID = false; try { var response = await SendRequestAsync(request).ConfigureAwait(false); // Process response var mlcl = DacpUtility.GetResponseNodes(response.Nodes.First(n => n.Key == "mlcl").Value); var nodes = DacpNodeDictionary.Parse(mlcl.First(n => n.Key == "mlit").Value); if (nodes.ContainsKey("ceSX")) { Int64 ceSX = nodes.GetLong("ceSX"); // Bit 0: Supports Play Queue if ((ceSX & (1 << 0)) != 0) { ServerSupportsPlayQueue = true; } // Bit 1: iTunes Radio? Appeared in iTunes 11.1.2 with the iTunes Radio DB. // Apple's Remote for iOS doesn't seem to use this bit to determine whether iTunes Radio is available. // Instead, it looks for an iTunes Radio database and checks whether it has any containers. // Bit 2: Genius Shuffle Enabled/Available if ((ceSX & (1 << 2)) != 0) { ServerSupportsGeniusShuffle = true; } } } catch { return(false); } return(true); }
private async Task <bool> GetServerInfoAsync() { DacpRequest request = new DacpRequest("/server-info"); request.IncludeSessionID = false; try { var response = await SendRequestAsync(request).ConfigureAwait(false); // Process response ServerVersion = response.HTTPResponse.Headers.GetValueOrDefault("DAAP-Server"); var nodes = DacpNodeDictionary.Parse(response.Nodes); ServerName = nodes.GetString("minm"); //ServerVersion = nodes.GetInt("aeSV"); //ServerDMAPVersion = nodes.GetInt("mpro"); //ServerDAAPVersion = nodes.GetInt("apro"); // MAC addresses if (nodes.ContainsKey("msml")) { List <string> macAddresses = new List <string>(); var addressNodes = DacpUtility.GetResponseNodes(nodes["msml"]).Where(n => n.Key == "msma").Select(n => n.Value); foreach (var addressNode in addressNodes) { var address = BitConverter.ToInt64(addressNode, 0); address = address >> 16; macAddresses.Add(address.ToString("X12")); } ServerMacAddresses = macAddresses.ToArray(); } } catch { return(false); } return(true); }
private async Task <bool> GetPlayStatusUpdateAsync(CancellationToken cancellationToken) { // Do not pass the cancellation token to the HTTP request since canceling a request will cause iTunes to close the current session. DacpRequest request = new DacpRequest("/ctrl-int/1/playstatusupdate"); request.QueryParameters["revision-number"] = _playStatusRevisionNumber.ToString(); try { var response = await SendRequestAsync(request).ConfigureAwait(false); // Do we still need to process this response? if (cancellationToken.IsCancellationRequested) { return(false); } // Process response var nodes = DacpNodeDictionary.Parse(response.Nodes); _playStatusRevisionNumber = nodes.GetInt("cmsr"); // Current item and container IDs if (nodes.ContainsKey("canp")) { byte[] value = nodes["canp"]; byte[] dbID = { value[0], value[1], value[2], value[3] }; byte[] containerID = { value[4], value[5], value[6], value[7] }; byte[] containerItemID = { value[8], value[9], value[10], value[11] }; byte[] itemID = { value[12], value[13], value[14], value[15] }; CurrentDatabaseID = dbID.GetInt32Value(); CurrentContainerID = containerID.GetInt32Value(); CurrentContainerItemID = containerItemID.GetInt32Value(); CurrentItemID = itemID.GetInt32Value(); } else { CurrentDatabaseID = 0; CurrentContainerID = 0; CurrentContainerItemID = 0; CurrentItemID = 0; } CurrentItemSignature = string.Format("{0}|{1}|{2}|{3}", CurrentDatabaseID, CurrentContainerID, CurrentContainerItemID, CurrentItemID); // Current item info CurrentArtistName = nodes.GetString("cana"); CurrentAlbumName = nodes.GetString("canl"); CurrentSongName = nodes.GetString("cann"); CurrentAlbumPersistentID = (UInt64)nodes.GetLong("asai"); // Play state CurrentPlayState = (PlayState)nodes.GetByte("caps"); // Track time UpdateTrackTime(nodes.GetInt("cast"), nodes.GetNullableInt("cant")); // Shuffle int caas = nodes.GetInt("caas"); IsShuffleAvailable = (caas & (1 << 1)) != 0; CurrentShuffleMode = nodes.GetBool("cash"); // Repeat int caar = nodes.GetInt("caar"); IsRepeatOneAvailable = (caar & (1 << 1)) != 0; IsRepeatAllAvailable = (caar & (1 << 2)) != 0; IsRepeatAvailable = (IsRepeatOneAvailable || IsRepeatAllAvailable); CurrentRepeatMode = (RepeatMode)nodes.GetByte("carp"); //CurrentMediaKind = nodes.GetInt("cmmk"); //ShowUserRating = nodes.GetBool("casu"); // dacp.visualizer IsVisualizerEnabled = nodes.GetBool("cavs"); // dacp.visualizerenabled IsVisualizerAvailable = nodes.GetBool("cave"); // dacp.fullscreen IsFullScreenModeEnabled = nodes.GetBool("cafs"); // dacp.fullscreenenabled IsFullScreenModeAvailable = nodes.GetBool("cafe"); // iTunes Radio iTunesRadioControlState newiTunesRadioControlState = 0; if (iTunesRadioDatabase != null && iTunesRadioDatabase.ID == CurrentDatabaseID) { IsPlayingiTunesRadio = true; CurrentiTunesRadioStationName = nodes.GetString("ceNR"); // caks = 1 when the next button is disabled, and 2 when it's enabled if (nodes.GetByte("caks") != 1) { newiTunesRadioControlState |= iTunesRadioControlState.NextButtonEnabled; } // "aelb" indicates whether the star button (iTunes Radio menu) should be enabled, but this only seems to be set to true // when connected via Home Sharing. This parameter is missing when an ad is playing, so use this to determine whether // the menu should be enabled. if (nodes.ContainsKey("aelb")) { newiTunesRadioControlState |= iTunesRadioControlState.MenuEnabled; } if (nodes.GetByte("aels") == 2) { newiTunesRadioControlState |= iTunesRadioControlState.CurrentSongFavorited; } } else { IsPlayingiTunesRadio = false; } CurrentiTunesRadioControlState = newiTunesRadioControlState; IsTrackTimePositionBarEnabled = nodes.GetBool("casc", true); // Genius Shuffle IsPlayingGeniusShuffle = nodes.GetBool("ceGs"); // There are two other nodes related to Genius Shuffle, "ceGS" and "aeGs" (currently unknown) if (CurrentPlayState == PlayState.FastForward || CurrentPlayState == PlayState.Rewind) { BeginRepeatedTrackTimeRequests(); } await GetVolumeLevelAsync().ConfigureAwait(false); await GetSpeakersAsync().ConfigureAwait(false); //var volumeTask = UpdateCurrentVolumeLevelAsync(); //var userRatingTask = UpdateCurrentSongUserRatingAsync(); //var playQueueTask = UpdatePlayQueueContentsAsync(); //Task[] tasks = new[] { volumeTask, userRatingTask, playQueueTask }; #if WP7 //await TaskEx.WhenAll(tasks).ConfigureAwait(false); #else //await Task.WhenAll(tasks).ConfigureAwait(false); #endif //SubmitGetSpeakersRequest(); PlayStatusUpdated.RaiseOnUIThread(this, new EventArgs()); } catch { return(false); } return(true); }
internal Task <IDacpList> GetAlphaGroupedListAsync <T>(DacpRequest request, Func <DacpNodeDictionary, T> itemGenerator, string listKey = DacpUtility.DefaultListKey) { return(GetAlphaGroupedListAsync(request, b => itemGenerator(DacpNodeDictionary.Parse(b)), listKey)); }
public Task <bool> SendPlayResumeCommandAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/playresume"); return(SendCommandAsync(request)); }
public Task <bool> SendBeginFastForwardCommandAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/beginff"); return(SendCommandAsync(request)); }
public Task <bool> SendBeginRewindCommandAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/beginrew"); return(SendCommandAsync(request)); }
public Task <bool> SendNextTrackCommandAsync() { DacpRequest request = new DacpRequest("/ctrl-int/1/nextitem"); return(SendCommandAsync(request)); }
private async Task <bool> GetDatabasesAsync() { DacpRequest request = new DacpRequest("/databases"); try { var databases = await GetListAsync(request, n => DacpDatabase.GetDatabase(this, n)).ConfigureAwait(false); if (databases == null || databases.Count == 0) { return(false); } List <DacpDatabase> newSharedDatabases = new List <DacpDatabase>(); for (int i = 0; i < databases.Count; i++) { var db = databases[i]; // The main database will be first in the list if (i == 0) { if (MainDatabase != null && MainDatabase.ID == db.ID) { continue; } bool success = await db.RequestContainersAsync().ConfigureAwait(false); if (!success) { return(false); } MainDatabase = db; continue; } // Shared database if (db.Type == DatabaseType.Shared) { newSharedDatabases.Add(db); continue; } // Internet Radio if (db.Type == DatabaseType.InternetRadio) { if (InternetRadioDatabase != null && InternetRadioDatabase.ID == db.ID) { continue; } InternetRadioDatabase = db; continue; } // iTunes Radio if (db.Type == DatabaseType.iTunesRadio) { if (iTunesRadioDatabase != null && iTunesRadioDatabase.ID == db.ID) { continue; } iTunesRadioDatabase = (iTunesRadioDatabase)db; // Attempt to load the stations asynchronously to determine whether iTunes Radio is enabled. var task = iTunesRadioDatabase.RequestStationsAsync(); continue; } } // Update shared databases Dictionary <int, DacpDatabase> removedSharedDBs = SharedDatabases.ToDictionary(db => db.ID); foreach (var sharedDB in newSharedDatabases) { removedSharedDBs.Remove(sharedDB.ID); if (SharedDatabases.Any(db => db.ID == sharedDB.ID)) { continue; } SharedDatabases.Add(sharedDB); } foreach (DacpDatabase db in removedSharedDBs.Values) { SharedDatabases.Remove(db); } Databases.Clear(); Databases.AddRange(databases); } catch { return(false); } return(true); }