Add an ability to get player state and execute commands

This commit is contained in:
Victor 2017-08-29 09:25:09 +03:00
parent 48cfa93e5c
commit d149f8625f
2 changed files with 67 additions and 3 deletions

View File

@ -1,6 +1,7 @@
module aimpremote; module aimpremote;
import core.sys.windows.windows; import core.sys.windows.windows;
import std.typecons : Nullable;
private const wstring AIMPRemoteAccessClass = "AIMP2_RemoteInfo"; private const wstring AIMPRemoteAccessClass = "AIMP2_RemoteInfo";
private const int AIMPRemoteAccessMapFileSize = 2048; private const int AIMPRemoteAccessMapFileSize = 2048;
@ -26,6 +27,21 @@ private struct AIMPRemoteFileInfo
DWORD[6] deprecated2; DWORD[6] deprecated2;
}; };
private const int WM_AIMP_COMMAND = WM_USER + 0x75;
private const int WM_AIMP_NOTIFY = WM_USER + 0x76;
private const int WM_AIMP_PROPERTY = WM_USER + 0x77;
private const int AIMP_RA_PROPVALUE_GET = 0;
private const int AIMP_RA_PROPVALUE_SET = 1;
private const int AIMP_RA_PROPERTY_MASK = 0xFFFFFFF0;
private const int AIMP_RA_PROPERTY_PLAYER_STATE = 0x40;
private const int AIMP_RA_PROPERTY_VOLUME = 0x50;
private const int AIMP_RA_CMD_BASE = 10;
private const int AIMP_RA_CMD_NEXT = AIMP_RA_CMD_BASE + 7;
private const int AIMP_RA_CMD_PREV = AIMP_RA_CMD_BASE + 8;
private enum TagItem { private enum TagItem {
Album, Artist, Date, FileName, Genre, Title Album, Artist, Date, FileName, Genre, Title
} }
@ -36,12 +52,55 @@ public struct TrackInfo {
wstring genre; wstring genre;
}; };
public static TrackInfo getInfo() { public enum PlayerState {
Off, Stopped, Paused, Playing
}
public static PlayerState getPlayerState() {
auto hwnd = findPlayerWindow();
if (hwnd == null) {
return PlayerState.Off;
}
const auto state = SendMessage(hwnd, WM_AIMP_PROPERTY,
AIMP_RA_PROPERTY_PLAYER_STATE | AIMP_RA_PROPVALUE_GET, 0);
switch (state) {
default: return PlayerState.Stopped;
case 1: return PlayerState.Paused;
case 2: return PlayerState.Playing;
}
}
public static void setVolume(ubyte volume) {
auto hwnd = findPlayerWindow();
if (hwnd != null) {
SendMessage(hwnd, WM_AIMP_PROPERTY,
AIMP_RA_PROPERTY_VOLUME | AIMP_RA_PROPVALUE_SET, volume);
}
}
public static void nextTrack() {
auto hwnd = findPlayerWindow();
if (hwnd != null) {
SendMessage(hwnd, WM_AIMP_COMMAND, AIMP_RA_CMD_NEXT, 0);
}
}
public static Nullable!TrackInfo getInfo() {
import std.conv : to; import std.conv : to;
import std.traits : EnumMembers; import std.traits : EnumMembers;
Nullable!TrackInfo result = Nullable!TrackInfo.init;
auto haimp = OpenFileMapping(FILE_MAP_READ, 0, AIMPRemoteAccessClass.ptr); auto haimp = OpenFileMapping(FILE_MAP_READ, 0, AIMPRemoteAccessClass.ptr);
if (haimp == null) {
result.nullify();
return result;
}
const auto hfilemap = MapViewOfFile(haimp, FILE_MAP_READ, 0, 0, AIMPRemoteAccessMapFileSize); const auto hfilemap = MapViewOfFile(haimp, FILE_MAP_READ, 0, 0, AIMPRemoteAccessMapFileSize);
if (hfilemap == null) {
result.nullify();
return result;
}
AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap;
auto bytes = (cast(ubyte*) hfilemap)[0 .. AIMPRemoteAccessMapFileSize]; auto bytes = (cast(ubyte*) hfilemap)[0 .. AIMPRemoteAccessMapFileSize];
@ -65,11 +124,12 @@ public static TrackInfo getInfo() {
pbuff += length * wcharsize; pbuff += length * wcharsize;
} }
TrackInfo result = { TrackInfo r = {
artist: trackInfo[TagItem.Artist], artist: trackInfo[TagItem.Artist],
title: trackInfo[TagItem.Title], title: trackInfo[TagItem.Title],
genre: trackInfo[TagItem.Genre] genre: trackInfo[TagItem.Genre]
}; };
result = Nullable!TrackInfo(r);
return result; return result;
} }
@ -86,7 +146,7 @@ private static HWND findPlayerWindow() {
AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap; AIMPRemoteFileInfo* info = cast(AIMPRemoteFileInfo*) hfilemap;
write("Bitrate: "); write("Bitrate: ");
writeln(info.bitRate); writeln(info.bitRate);
write("Samplerate: "); write("Samlerate: ");
writeln(info.sampleRate); writeln(info.sampleRate);
write("fileSize: "); write("fileSize: ");
writeln(info.fileSize); writeln(info.fileSize);

View File

@ -10,6 +10,10 @@ void main()
http.handle.set(CurlOption.ssl_verifypeer, 0); http.handle.set(CurlOption.ssl_verifypeer, 0);
auto track = getInfo(); auto track = getInfo();
if (track.isNull) {
writeln("No data");
return;
}
auto content = post("https://annimon.com/json/nowplay", [ auto content = post("https://annimon.com/json/nowplay", [
"login" : "test", "login" : "test",