InfiniTime/src/components/ble/MusicService.cpp

224 lines
9.7 KiB
C++
Raw Normal View History

2021-05-16 23:16:50 +00:00
/* Copyright (C) 2020-2021 JF, Adam Pigg, Avamander
This file is part of InfiniTime.
InfiniTime is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
InfiniTime is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "components/ble/MusicService.h"
2020-11-15 14:05:51 +00:00
#include "systemtask/SystemTask.h"
#include <cstring>
namespace {
// 0000yyxx-78fc-48fe-8e23-433b3a1942d0
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
return ble_uuid128_t{
.u = {.type = BLE_UUID_TYPE_128},
.value = { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, x, y, 0x00, 0x00 }
};
}
// 00000000-78fc-48fe-8e23-433b3a1942d0
constexpr ble_uuid128_t BaseUuid() {
return CharUuid(0x00, 0x00);
}
constexpr ble_uuid128_t msUuid {BaseUuid()};
constexpr ble_uuid128_t msEventCharUuid {CharUuid(0x01, 0x00)};
constexpr ble_uuid128_t msStatusCharUuid {CharUuid(0x02, 0x00)};
constexpr ble_uuid128_t msArtistCharUuid {CharUuid(0x03, 0x00)};
constexpr ble_uuid128_t msTrackCharUuid {CharUuid(0x04, 0x00)};
constexpr ble_uuid128_t msAlbumCharUuid {CharUuid(0x05, 0x00)};
constexpr ble_uuid128_t msPositionCharUuid {CharUuid(0x06, 0x00)};
constexpr ble_uuid128_t msTotalLengthCharUuid {CharUuid(0x07, 0x00)};
constexpr ble_uuid128_t msTrackNumberCharUuid {CharUuid(0x08, 0x00)};
constexpr ble_uuid128_t msTrackTotalCharUuid {CharUuid(0x09, 0x00)};
constexpr ble_uuid128_t msPlaybackSpeedCharUuid {CharUuid(0x0a, 0x00)};
constexpr ble_uuid128_t msRepeatCharUuid {CharUuid(0x0b, 0x00)};
constexpr ble_uuid128_t msShuffleCharUuid {CharUuid(0x0c, 0x00)};
constexpr uint8_t MaxStringSize {40};
int MusicCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(conn_handle, attr_handle, ctxt);
}
}
Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask& system) : m_system(system) {
2021-06-07 22:52:27 +00:00
characteristicDefinition[0] = {.uuid = &msEventCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_NOTIFY,
.val_handle = &eventHandle};
2021-06-07 22:52:27 +00:00
characteristicDefinition[1] = {.uuid = &msStatusCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[2] = {.uuid = &msTrackCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[3] = {.uuid = &msArtistCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[4] = {.uuid = &msAlbumCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[5] = {.uuid = &msPositionCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[6] = {.uuid = &msTotalLengthCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[7] = {.uuid = &msTotalLengthCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[8] = {.uuid = &msTrackNumberCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[9] = {.uuid = &msTrackTotalCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[10] = {.uuid = &msPlaybackSpeedCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[11] = {.uuid = &msRepeatCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
2021-06-07 22:52:27 +00:00
characteristicDefinition[12] = {.uuid = &msShuffleCharUuid.u,
.access_cb = MusicCallback,
.arg = this,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
characteristicDefinition[13] = {0};
serviceDefinition[0] = {
2021-06-07 22:52:27 +00:00
.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &msUuid.u, .characteristics = characteristicDefinition};
serviceDefinition[1] = {0};
}
void Pinetime::Controllers::MusicService::Init() {
uint8_t res = 0;
res = ble_gatts_count_cfg(serviceDefinition);
ASSERT(res == 0);
res = ble_gatts_add_svcs(serviceDefinition);
ASSERT(res == 0);
}
int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
size_t bufferSize = notifSize;
2022-03-14 20:03:08 +00:00
if (notifSize > MaxStringSize) {
bufferSize = MaxStringSize;
}
char data[bufferSize + 1];
os_mbuf_copydata(ctxt->om, 0, bufferSize, data);
if (notifSize > bufferSize) {
data[bufferSize-1] = '.';
data[bufferSize-2] = '.';
data[bufferSize-3] = '.';
}
data[bufferSize] = '\0';
char* s = &data[0];
2021-06-07 22:52:27 +00:00
if (ble_uuid_cmp(ctxt->chr->uuid, &msArtistCharUuid.u) == 0) {
artistName = s;
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackCharUuid.u) == 0) {
trackName = s;
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msAlbumCharUuid.u) == 0) {
albumName = s;
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msStatusCharUuid.u) == 0) {
playing = s[0];
// These variables need to be updated, because the progress may not be updated immediately,
// leading to getProgress() returning an incorrect position.
if (playing) {
trackProgressUpdateTime = xTaskGetTickCount();
} else {
trackProgress += static_cast<int>((static_cast<float>(xTaskGetTickCount() - trackProgressUpdateTime) / 1024.0f) * getPlaybackSpeed());
}
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msRepeatCharUuid.u) == 0) {
repeat = s[0];
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msShuffleCharUuid.u) == 0) {
shuffle = s[0];
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msPositionCharUuid.u) == 0) {
trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
trackProgressUpdateTime = xTaskGetTickCount();
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTotalLengthCharUuid.u) == 0) {
trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackNumberCharUuid.u) == 0) {
trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msTrackTotalCharUuid.u) == 0) {
tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
2021-06-07 22:52:27 +00:00
} else if (ble_uuid_cmp(ctxt->chr->uuid, &msPlaybackSpeedCharUuid.u) == 0) {
playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
}
}
return 0;
}
std::string Pinetime::Controllers::MusicService::getAlbum() const {
return albumName;
}
std::string Pinetime::Controllers::MusicService::getArtist() const {
return artistName;
}
std::string Pinetime::Controllers::MusicService::getTrack() const {
return trackName;
}
bool Pinetime::Controllers::MusicService::isPlaying() const {
return playing;
}
float Pinetime::Controllers::MusicService::getPlaybackSpeed() const {
return playbackSpeed;
}
2022-04-24 09:38:09 +00:00
int Pinetime::Controllers::MusicService::getProgress() const {
if (isPlaying()) {
return trackProgress + static_cast<int>((static_cast<float>(xTaskGetTickCount() - trackProgressUpdateTime) / 1024.0f) * getPlaybackSpeed());
}
return trackProgress;
}
int Pinetime::Controllers::MusicService::getTrackLength() const {
return trackLength;
}
void Pinetime::Controllers::MusicService::event(char event) {
auto* om = ble_hs_mbuf_from_flat(&event, 1);
uint16_t connectionHandle = m_system.nimble().connHandle();
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
return;
}
ble_gattc_notify_custom(connectionHandle, eventHandle, om);
2021-06-07 22:52:27 +00:00
}