Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ debian/krode.substvars

# Junk
.c*

# Built binary
krode
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# krode

Delete onboard recordings from the **Rode Interview PRO** wireless microphone transmitter on Linux.
Delete onboard recordings from supported **Rode** wireless microphone transmitters on Linux.

Rode only officially supports this through their proprietary **Rode Central** software (Windows/macOS). This tool replicates the delete function via the device's USB HID control interface, which is accessible on Linux.

Expand Down Expand Up @@ -46,7 +46,7 @@ sudo usermod -aG plugdev $USER

## Usage

Connect the Interview PRO TX unit via USB, then:
Connect a supported TX unit via USB, then:

```
krode delete
Expand All @@ -56,7 +56,7 @@ This deletes all onboard recordings. The device confirms with a status code of 1

## Protocol

The Interview PRO presents as a composite USB device:
Supported transmitters present a USB HID control interface:

- **Mass Storage (SCSI)** — read-only; used to copy WAV files to the host
- **HID (vendor-specific)** — used for control commands
Expand All @@ -67,6 +67,7 @@ Device identifiers:
|------|-----|-----|
| Interview PRO TX (unit 1) | `0x19F7` | `0x0063` |
| Interview PRO TX (unit 2) | `0x19F7` | `0x0068` |
| Wireless PRO TX (both units) | `0x19F7` | `0x0056` |

### Delete command

Expand All @@ -85,7 +86,7 @@ HID Output Report, 17 bytes, sent via SET_REPORT:

### Device ACK

Response arrives on endpoint `0x81` (URB_INTERRUPT IN), 17 bytes:
Response arrives on the HID interrupt IN endpoint, 17 bytes:

```
02 4A 41 64 00 00 00 00 00 00 00 00 00 00 00 00 00
Expand All @@ -101,6 +102,8 @@ Response arrives on endpoint `0x81` (URB_INTERRUPT IN), 17 bytes:
Reverse-engineered from USB traffic captured with Wireshark + USBPcap on Windows.
Confirmed working on TX unit 1 (PID `0x0063`). PID `0x0068` is untested for delete.

Wireless PRO TX PID `0x0056` is supported by device ID.

## Support

For questions, troubleshooting, or general discussion, please use the
Expand Down
Binary file removed krode
Binary file not shown.
97 changes: 76 additions & 21 deletions krode.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* krode - delete onboard recordings from Rode Interview PRO on Linux
* krode - delete onboard recordings from supported Rode transmitters on Linux
*
* Usage: krode delete
*
Expand All @@ -18,15 +18,28 @@

#define RODE_VID 0x19F7

/* Both TX units seen on Interview PRO */
#define RODE_PID_TX1 0x0063
#define RODE_PID_TX2 0x0068
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

struct rode_device {
unsigned short pid;
const char *name;
};

static const struct rode_device rode_devices[] = {
{ 0x0063, "Interview PRO TX (unit 1)" },
{ 0x0068, "Interview PRO TX (unit 2)" },

// Note: Unlike Interview PRO TX units, Wireless PRO TX units, as-tested, advertise
// the same USB PID. Matching on hidraw paths is required when both Wireless
// PRO TX units are plugged in.
{ 0x0056, "Wireless PRO TX" },
};

#define REPORT_SIZE 17
#define CMD_DELETE 0x4A
#define DELETE_ALL 0x01

static int delete_recordings(hid_device *dev, unsigned short pid)
static int delete_recordings(hid_device *dev, const struct rode_device *device)
{
unsigned char buf[REPORT_SIZE];
int ret;
Expand All @@ -36,7 +49,7 @@ static int delete_recordings(hid_device *dev, unsigned short pid)
buf[1] = CMD_DELETE; /* 0x4A - delete command */
buf[2] = DELETE_ALL; /* 0x01 - delete all */

printf("Sending delete command to PID 0x%04X...\n", pid);
printf("Sending delete command to %s (PID 0x%04X)...\n", device->name, device->pid);

ret = hid_write(dev, buf, sizeof(buf));
if (ret < 0) {
Expand All @@ -62,30 +75,63 @@ static int delete_recordings(hid_device *dev, unsigned short pid)
}

/* Print raw response for debugging */
printf("Response: ");
for (int i = 0; i < ret; i++)
printf("%02x ", buf[i]);
printf("\n");
fprintf(stderr, "Unexpected response: ");

for (int i = 0; i < ret; i++) {
fprintf(stderr, "%02x ", buf[i]);
}

return 0;
fprintf(stderr, "\n");

return -1;
}

static int run_on_pid(unsigned short pid)
static int run_on_device(const struct rode_device *device)
{
struct hid_device_info *devs;
struct hid_device_info *cur;
hid_device *dev;
int found = 0;
int failed = 0;

dev = hid_open(RODE_VID, pid, NULL);
if (!dev)
devs = hid_enumerate(RODE_VID, device->pid);
if (!devs)
return -1; /* not found, not an error if other PID works */

delete_recordings(dev, pid);
hid_close(dev);
return 0;
// Enumerate all found devices
for (cur = devs; cur; cur = cur->next) {
if (!cur->path)
continue;

found++;

printf("Opening %s (PID 0x%04X, path %s)...\n", device->name, device->pid, cur->path);

dev = hid_open_path(cur->path);
if (!dev) {
fprintf(stderr, "hid_open_path failed for %s\n", cur->path);
failed++;
continue;
}

if (delete_recordings(dev, device) != 0)
failed++;

hid_close(dev);
}

hid_free_enumeration(devs);

if (found == 0)
return -1;

return failed == 0 ? 0 : -2;
}

int main(int argc, char *argv[])
{
int found = 0;
int failed = 0;

if (argc < 2 || strcmp(argv[1], "delete") != 0) {
fprintf(stderr, "Usage: %s delete\n", argv[0]);
Expand All @@ -98,18 +144,27 @@ int main(int argc, char *argv[])
return 1;
}

if (run_on_pid(RODE_PID_TX1) == 0) found++;
if (run_on_pid(RODE_PID_TX2) == 0) found++;
for (size_t i = 0; i < ARRAY_SIZE(rode_devices); i++) {
int ret = run_on_device(&rode_devices[i]);

if (ret == -1)
continue;

found++;
if (ret == 0)
continue;
failed++;
}

if (found == 0) {
fprintf(stderr,
"No Rode Interview PRO found. Check USB connection.\n");
"No supported Rode transmitter found. Check USB connection.\n");
fprintf(stderr,
"You may need to run as root or add a udev rule.\n");
hid_exit();
return 1;
}

hid_exit();
return 0;
return failed == 0 ? 0 : 1;
}