1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-30 20:45:49 +01:00

Amazfit Cor: implement basic music controls

Play/pause and skip to previous/next song work. The currently playing song
name is shown on the Cor. The track length and progress are now shown as
we don't know how to send these yet.
This commit is contained in:
Daniele Gobbetti 2018-08-06 23:11:40 +02:00
parent cc3c70b161
commit 3fac021ff2
3 changed files with 130 additions and 2 deletions

View File

@ -75,4 +75,16 @@ public class MusicSpec {
result = 31 * result + trackNr; result = 31 * result + trackNr;
return result; return result;
} }
@Override
public String toString() {
return "MusicSpec{" +
"artist='" + artist + '\'' +
", album='" + album + '\'' +
", track='" + track + '\'' +
", duration=" + duration +
", trackCount=" + trackCount +
", trackNr=" + trackNr +
'}';
}
} }

View File

@ -71,4 +71,15 @@ public class MusicStateSpec {
result = 31 * result + (int) repeat; result = 31 * result + (int) repeat;
return result; return result;
} }
@Override
public String toString() {
return "MusicStateSpec{" +
"state=" + state +
", position=" + position +
", playRate=" + playRate +
", shuffle=" + shuffle +
", repeat=" + repeat +
'}';
}
} }

View File

@ -34,6 +34,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -171,6 +173,10 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
private RealtimeSamplesSupport realtimeSamplesSupport; private RealtimeSamplesSupport realtimeSamplesSupport;
private boolean alarmClockRinging; private boolean alarmClockRinging;
private boolean isMusicAppStarted = false;
private MusicSpec bufferMusicSpec = null;
private MusicStateSpec bufferMusicStateSpec = null;
public HuamiSupport() { public HuamiSupport() {
this(LOG); this(LOG);
} }
@ -726,12 +732,102 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
@Override @Override
public void onSetMusicState(MusicStateSpec stateSpec) { public void onSetMusicState(MusicStateSpec stateSpec) {
// not supported if (bufferMusicStateSpec != stateSpec)
bufferMusicStateSpec = stateSpec;
sendMusicStateToDevice();
} }
@Override @Override
public void onSetMusicInfo(MusicSpec musicSpec) { public void onSetMusicInfo(MusicSpec musicSpec) {
// not supported if (bufferMusicSpec != musicSpec)
bufferMusicSpec = musicSpec;
if (!isMusicAppStarted) {
return;
}
sendMusicStateToDevice();
}
private void sendMusicStateToDevice() {
if (characteristicChunked == null) {
return;
}
if (bufferMusicSpec == null && bufferMusicStateSpec == null) {
try {
TransactionBuilder builder = performInitialized("send dummy playback info to enable music controls");
writeToChunked(builder, 3, new byte[]{1, 0, 1, 0, 0, 0, 1, 0});
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Unable to send dummy music controls");
}
return;
}
byte flags = 0x00;
flags |= 0x01;
int length = 8;
if (bufferMusicSpec.track != null && bufferMusicSpec.track.getBytes().length > 0) {
length += bufferMusicSpec.track.getBytes().length + 1;
flags |= 0x02;
}
if (bufferMusicSpec.album != null && bufferMusicSpec.album.getBytes().length > 0) {
length += bufferMusicSpec.album.getBytes().length + 1;
flags |= 0x04;
}
if (bufferMusicSpec.artist != null && bufferMusicSpec.artist.getBytes().length > 0) {
length += bufferMusicSpec.artist.getBytes().length + 1;
flags |= 0x08;
}
// LOG.info("Music flags are: " + (flags & 0xff));
try {
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put(flags);
byte state;
switch (bufferMusicStateSpec.state) {
case MusicStateSpec.STATE_PLAYING:
state = 1;
break;
default:
state = 0;
}
buf.put(state);
buf.put(new byte[]{0x1, 0x0, 0x0, 0x0}); //unknown
buf.put(new byte[]{0x1,0x0}); //show track
// buf.put(new byte[]{0x1,0x1}); //show album
if (bufferMusicSpec.track != null && bufferMusicSpec.track.getBytes().length > 0) {
buf.put(bufferMusicSpec.track.getBytes());
buf.put((byte) 0);
}
if (bufferMusicSpec.album != null && bufferMusicSpec.album.getBytes().length > 0) {
buf.put(bufferMusicSpec.album.getBytes());
buf.put((byte) 0);
}
if (bufferMusicSpec.artist != null && bufferMusicSpec.artist.getBytes().length > 0) {
buf.put(bufferMusicSpec.artist.getBytes());
buf.put((byte) 0);
}
TransactionBuilder builder = performInitialized("send playback info");
writeToChunked(builder, 3, buf.array());
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Unable to send playback state");
}
// LOG.info("Sent music: " + bufferMusicSpec.toString() + " " + bufferMusicStateSpec.toString());
} }
@Override @Override
@ -1012,6 +1108,15 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
case 6: case 6:
deviceEventMusicControl.event = GBDeviceEventMusicControl.Event.VOLUMEDOWN; deviceEventMusicControl.event = GBDeviceEventMusicControl.Event.VOLUMEDOWN;
break; break;
case (byte) 224:
LOG.info("Music app started");
isMusicAppStarted = true;
sendMusicStateToDevice();
break;
case (byte) 225:
LOG.info("Music app terminated");
isMusicAppStarted = false;
break;
default: default:
LOG.info("unhandled music control event " + value[1]); LOG.info("unhandled music control event " + value[1]);
return; return;