mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-03-26 07:55:31 +00:00
[Linux] Implement renaming airpods (#88)
* [Linux] Implement rename airpods * [Linux] Get airpods name from airpods metadata * [Linux] Rename AirPods: Ui improvements --------- Co-authored-by: Tim Gromeyer <tim.gromeyer@trans4mation.de>
This commit is contained in:
@@ -72,5 +72,23 @@ ApplicationWindow {
|
|||||||
anchors.top: parent.bottom
|
anchors.top: parent.bottom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: newNameField
|
||||||
|
placeholderText: airPodsTrayApp.deviceName
|
||||||
|
maximumLength: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Rename"
|
||||||
|
onClicked: {
|
||||||
|
airPodsTrayApp.renameAirPods(newNameField.text)
|
||||||
|
// Optional: newNameField.text = "" // Clear field after rename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,11 +74,26 @@ namespace AirPodsPackets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Rename
|
||||||
|
{
|
||||||
|
static QByteArray getPacket(const QString &newName)
|
||||||
|
{
|
||||||
|
QByteArray nameBytes = newName.toUtf8(); // Convert name to UTF-8
|
||||||
|
quint8 size = static_cast<char>(nameBytes.size()); // Name length (1 byte)
|
||||||
|
QByteArray packet = QByteArray::fromHex("040004001A0001"); // Header
|
||||||
|
packet.append(size); // Append size byte
|
||||||
|
packet.append('\0'); // Append null byte
|
||||||
|
packet.append(nameBytes); // Append name bytes
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parsing Headers
|
// Parsing Headers
|
||||||
namespace Parse
|
namespace Parse
|
||||||
{
|
{
|
||||||
static const QByteArray EAR_DETECTION = QByteArray::fromHex("040004000600");
|
static const QByteArray EAR_DETECTION = QByteArray::fromHex("040004000600");
|
||||||
static const QByteArray BATTERY_STATUS = QByteArray::fromHex("040004000400");
|
static const QByteArray BATTERY_STATUS = QByteArray::fromHex("040004000400");
|
||||||
|
static const QByteArray METADATA = QByteArray::fromHex("040004001d");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
110
linux/main.cpp
110
linux/main.cpp
@@ -20,6 +20,7 @@ class AirPodsTrayApp : public QObject {
|
|||||||
Q_PROPERTY(bool conversationalAwareness READ conversationalAwareness WRITE setConversationalAwareness NOTIFY conversationalAwarenessChanged)
|
Q_PROPERTY(bool conversationalAwareness READ conversationalAwareness WRITE setConversationalAwareness NOTIFY conversationalAwarenessChanged)
|
||||||
Q_PROPERTY(int adaptiveNoiseLevel READ adaptiveNoiseLevel WRITE setAdaptiveNoiseLevel NOTIFY adaptiveNoiseLevelChanged)
|
Q_PROPERTY(int adaptiveNoiseLevel READ adaptiveNoiseLevel WRITE setAdaptiveNoiseLevel NOTIFY adaptiveNoiseLevelChanged)
|
||||||
Q_PROPERTY(bool adaptiveModeActive READ adaptiveModeActive NOTIFY noiseControlModeChanged)
|
Q_PROPERTY(bool adaptiveModeActive READ adaptiveModeActive NOTIFY noiseControlModeChanged)
|
||||||
|
Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AirPodsTrayApp(bool debugMode) : debugMode(debugMode) {
|
AirPodsTrayApp(bool debugMode) : debugMode(debugMode) {
|
||||||
@@ -100,6 +101,7 @@ public:
|
|||||||
bool conversationalAwareness() const { return m_conversationalAwareness; }
|
bool conversationalAwareness() const { return m_conversationalAwareness; }
|
||||||
bool adaptiveModeActive() const { return m_noiseControlMode == NoiseControlMode::Adaptive; }
|
bool adaptiveModeActive() const { return m_noiseControlMode == NoiseControlMode::Adaptive; }
|
||||||
int adaptiveNoiseLevel() const { return m_adaptiveNoiseLevel; }
|
int adaptiveNoiseLevel() const { return m_adaptiveNoiseLevel; }
|
||||||
|
QString deviceName() const { return m_deviceName; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool debugMode;
|
bool debugMode;
|
||||||
@@ -272,6 +274,37 @@ public slots:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renameAirPods(const QString &newName)
|
||||||
|
{
|
||||||
|
if (newName.isEmpty())
|
||||||
|
{
|
||||||
|
LOG_WARN("Cannot set empty name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newName.size() > 32)
|
||||||
|
{
|
||||||
|
LOG_WARN("Name is too long, must be 32 characters or less");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newName == m_deviceName)
|
||||||
|
{
|
||||||
|
LOG_INFO("Name is already set to: " << newName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray packet = AirPodsPackets::Rename::getPacket(newName);
|
||||||
|
if (writePacketToSocket(packet, "Rename packet written: "))
|
||||||
|
{
|
||||||
|
LOG_INFO("Sent rename command for new name: " << newName);
|
||||||
|
m_deviceName = newName;
|
||||||
|
emit deviceNameChanged(newName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to send rename command: socket not open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool writePacketToSocket(const QByteArray &packet, const QString &logMessage)
|
bool writePacketToSocket(const QByteArray &packet, const QString &logMessage)
|
||||||
{
|
{
|
||||||
if (socket && socket->isOpen())
|
if (socket && socket->isOpen())
|
||||||
@@ -363,6 +396,77 @@ private slots:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parseMetadata(const QByteArray &data)
|
||||||
|
{
|
||||||
|
// Verify the data starts with the METADATA header
|
||||||
|
if (!data.startsWith(AirPodsPackets::Parse::METADATA))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Invalid metadata packet: Incorrect header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = AirPodsPackets::Parse::METADATA.size(); // Start after the header
|
||||||
|
|
||||||
|
// Check if there is enough data to skip the initial bytes (based on example structure)
|
||||||
|
if (data.size() < pos + 6)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Metadata packet too short to parse initial bytes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pos += 6; // Skip 6 bytes after the header as per example structure
|
||||||
|
|
||||||
|
auto extractString = [&data, &pos]() -> QString
|
||||||
|
{
|
||||||
|
if (pos >= data.size())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
int start = pos;
|
||||||
|
while (pos < data.size() && data.at(pos) != '\0')
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
QString str = QString::fromUtf8(data.mid(start, pos - start));
|
||||||
|
if (pos < data.size())
|
||||||
|
{
|
||||||
|
++pos; // Move past the null terminator
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
m_deviceName = extractString();
|
||||||
|
QString modelNumber = extractString();
|
||||||
|
QString manufacturer = extractString();
|
||||||
|
QString hardwareVersion = extractString();
|
||||||
|
QString firmwareVersion = extractString();
|
||||||
|
QString firmwareVersion2 = extractString();
|
||||||
|
QString softwareVersion = extractString();
|
||||||
|
QString appIdentifier = extractString();
|
||||||
|
QString serialNumber1 = extractString();
|
||||||
|
QString serialNumber2 = extractString();
|
||||||
|
QString unknownNumeric = extractString();
|
||||||
|
QString unknownHash = extractString();
|
||||||
|
QString trailingByte = extractString();
|
||||||
|
|
||||||
|
emit deviceNameChanged(m_deviceName);
|
||||||
|
|
||||||
|
// Log extracted metadata
|
||||||
|
LOG_INFO("Parsed AirPods metadata:");
|
||||||
|
LOG_INFO("Device Name: " << m_deviceName);
|
||||||
|
LOG_INFO("Model Number: " << modelNumber);
|
||||||
|
LOG_INFO("Manufacturer: " << manufacturer);
|
||||||
|
LOG_INFO("Hardware Version: " << hardwareVersion);
|
||||||
|
LOG_INFO("Firmware Version: " << firmwareVersion);
|
||||||
|
LOG_INFO("Firmware Version2: " << firmwareVersion2);
|
||||||
|
LOG_INFO("Software Version: " << softwareVersion);
|
||||||
|
LOG_INFO("App Identifier: " << appIdentifier);
|
||||||
|
LOG_INFO("Serial Number 1: " << serialNumber1);
|
||||||
|
LOG_INFO("Serial Number 2: " << serialNumber2);
|
||||||
|
LOG_INFO("Unknown Numeric: " << unknownNumeric);
|
||||||
|
LOG_INFO("Unknown Hash: " << unknownHash);
|
||||||
|
LOG_INFO("Trailing Byte: " << trailingByte);
|
||||||
|
}
|
||||||
|
|
||||||
void connectToDevice(const QBluetoothDeviceInfo &device) {
|
void connectToDevice(const QBluetoothDeviceInfo &device) {
|
||||||
if (socket && socket->isOpen() && socket->peerAddress() == device.address()) {
|
if (socket && socket->isOpen() && socket->peerAddress() == device.address()) {
|
||||||
LOG_INFO("Already connected to the device: " << device.name());
|
LOG_INFO("Already connected to the device: " << device.name());
|
||||||
@@ -490,6 +594,10 @@ private slots:
|
|||||||
LOG_INFO("Received conversational awareness data");
|
LOG_INFO("Received conversational awareness data");
|
||||||
mediaController->handleConversationalAwareness(data);
|
mediaController->handleConversationalAwareness(data);
|
||||||
}
|
}
|
||||||
|
else if (data.startsWith(AirPodsPackets::Parse::METADATA))
|
||||||
|
{
|
||||||
|
parseMetadata(data);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Unrecognized packet format: " << data.toHex());
|
LOG_DEBUG("Unrecognized packet format: " << data.toHex());
|
||||||
@@ -714,6 +822,7 @@ signals:
|
|||||||
void batteryStatusChanged(const QString &status);
|
void batteryStatusChanged(const QString &status);
|
||||||
void conversationalAwarenessChanged(bool enabled);
|
void conversationalAwarenessChanged(bool enabled);
|
||||||
void adaptiveNoiseLevelChanged(int level);
|
void adaptiveNoiseLevelChanged(int level);
|
||||||
|
void deviceNameChanged(const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSystemTrayIcon *trayIcon;
|
QSystemTrayIcon *trayIcon;
|
||||||
@@ -733,6 +842,7 @@ private:
|
|||||||
NoiseControlMode m_noiseControlMode = NoiseControlMode::Off;
|
NoiseControlMode m_noiseControlMode = NoiseControlMode::Off;
|
||||||
bool m_conversationalAwareness = false;
|
bool m_conversationalAwareness = false;
|
||||||
int m_adaptiveNoiseLevel = 50;
|
int m_adaptiveNoiseLevel = 50;
|
||||||
|
QString m_deviceName;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user