mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-15 00:34:05 +09:00
uxplay.cpp: cleanup handling of DMAP/DAAP AirPlay-audio metadata
This commit is contained in:
182
uxplay.cpp
182
uxplay.cpp
@@ -570,7 +570,7 @@ static void append_hostname(std::string &server_name) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void parse_arguments (int argc, char *argv[]) {
|
||||
static void parse_arguments (int argc, char *argv[]) {
|
||||
// Parse arguments
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
@@ -776,6 +776,115 @@ void parse_arguments (int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
static void process_metadata(int count, const char *dmap_code, const unsigned char *dmap_len, const char* metadata, int datalen) {
|
||||
int dmap_type = 0;
|
||||
/* DMAP metadata items can be strings (dmap_type = 1); other types are byte, short, int, long, date, and list. *
|
||||
* The 4-character (4-letter) DMAP code string that begins the item identifies the type. */
|
||||
|
||||
/* dmap_len is the contents of last byte of 8-byte header preceding metadata, usually equals datalen */
|
||||
if (debug_log) {
|
||||
printf("%d: dmap_code [%s], dmap_len %d %d\n", count, dmap_code, (int) *dmap_len, datalen);
|
||||
}
|
||||
|
||||
/* String-type DMAP codes seen in Apple Music Radio are processed here. *
|
||||
* (DMAP codes "asal", "asar", "ascp", "asgn", "minm" ). TODO expand this */
|
||||
|
||||
if (datalen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dmap_code[0] == 'a' && dmap_code[1] == 's') {
|
||||
dmap_type = 1;
|
||||
switch (dmap_code[2]) {
|
||||
case 'a':
|
||||
switch (dmap_code[3]) {
|
||||
case 'a':
|
||||
printf("Album artist: "); /*asaa*/
|
||||
break;
|
||||
case 'l':
|
||||
printf("Album: "); /*asal*/
|
||||
break;
|
||||
case 'r':
|
||||
printf("Artist: "); /*asar*/
|
||||
break;
|
||||
default:
|
||||
dmap_type = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
switch (dmap_code[3]) {
|
||||
case 'm':
|
||||
printf("Comment: "); /*ascm*/
|
||||
break;
|
||||
case 'n':
|
||||
printf("Content description: "); /*ascn*/
|
||||
break;
|
||||
case 'p':
|
||||
printf("Composer: "); /*ascp*/
|
||||
break;
|
||||
case 't':
|
||||
printf("Category: "); /*asct*/
|
||||
break;
|
||||
default:
|
||||
dmap_type = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
switch (dmap_code[3]) {
|
||||
case 'a':
|
||||
printf("Sort Artist: "); /*assa*/
|
||||
break;
|
||||
case 'c':
|
||||
printf("Sort Composer: "); /*assc*/
|
||||
break;
|
||||
case 'l':
|
||||
printf("Sort Album artist: "); /*assl*/
|
||||
break;
|
||||
case 'n':
|
||||
printf("Sort Name: "); /*assn*/
|
||||
break;
|
||||
case 's':
|
||||
printf("Sort Series: "); /*asss*/
|
||||
break;
|
||||
case 'u':
|
||||
printf("Sort Album: "); /*assu*/
|
||||
break;
|
||||
default:
|
||||
dmap_type = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (strcmp(dmap_code, "asdt") == 0) {
|
||||
printf("Description: ");
|
||||
} else if (strcmp (dmap_code, "asfm") == 0) {
|
||||
printf("Format: ");
|
||||
} else if (strcmp (dmap_code, "asgn") == 0) {
|
||||
printf("Genre: ");
|
||||
} else {
|
||||
dmap_type = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (strcmp (dmap_code, "minm") == 0) {
|
||||
dmap_type = 1;
|
||||
printf("Title: ");
|
||||
}
|
||||
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
if (dmap_type == 1) {
|
||||
printf("%c", metadata[i]);
|
||||
} else if (debug_log) {
|
||||
if (i > 0 && i % 16 == 0) printf("\n");
|
||||
const unsigned char * data = (const unsigned char *) (metadata + i);
|
||||
printf("%2.2x ", (int) *data);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
std::vector<char> server_hw_addr;
|
||||
|
||||
@@ -1056,42 +1165,45 @@ extern "C" void audio_set_coverart(void *cls, const void *buffer, int buflen) {
|
||||
LOGI("coverart size %d written to %s", buflen, coverart_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void audio_set_metadata(void *cls, const void *buffer, int buflen) {
|
||||
unsigned char mark[]={ 0x00, 0x00, 0x00 }; /*daap seperator mark */
|
||||
if (buflen > 4) {
|
||||
printf("==============Audio Metadata=============\n");
|
||||
const unsigned char *metadata = (const unsigned char *) buffer;
|
||||
const char *tag = (const char *) buffer;
|
||||
int len;
|
||||
metadata += 4;
|
||||
for (int i = 4; i < buflen; i++) {
|
||||
if (memcmp (metadata, mark, 3) == 0 && (len = (int) *(metadata + 3))) {
|
||||
bool found_text = true;
|
||||
if (strcmp (tag, "asal") == 0) {
|
||||
printf("Album: ");
|
||||
} else if (strcmp (tag, "asar") == 0) {
|
||||
printf("Artist: ");
|
||||
} else if (strcmp (tag, "ascp") == 0) {
|
||||
printf("Composer: ");
|
||||
} else if (strcmp (tag, "asgn") == 0) {
|
||||
printf("Genre: ");
|
||||
} else if (strcmp (tag, "minm") == 0) {
|
||||
printf("Title: ");
|
||||
} else {
|
||||
found_text = false;
|
||||
}
|
||||
if (found_text) {
|
||||
const unsigned char *text = metadata + 4;
|
||||
for (int j = 0; j < len; j++) {
|
||||
printf("%c", *text);
|
||||
text++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
metadata++;
|
||||
tag++;
|
||||
const unsigned char mark[]={ 0x0, 0x0, 0x0 }; /*daap separator*/
|
||||
const char *dmap_code;
|
||||
const char *metadata = (const char *) buffer;
|
||||
const unsigned char *dmap_len;
|
||||
int datalen;
|
||||
int count = 0;
|
||||
|
||||
/* de-concatenate (and process) individual items in DMAP metadata sent by client in AirPlay Audio mode */
|
||||
|
||||
/* The metadata packet is a concatenated sequence of DMAP items each consisting of an 8-byte header, usually *
|
||||
* followed by data. No item is smaller than 8 bytes. The header is a DMAP code of 4 lower-case letters, then *
|
||||
* three null bytes and a final byte which is either the byte-length of data that follows, or the data itself. */
|
||||
|
||||
if ( buflen < 8 || memcmp (metadata + 4, mark, 3) != 0) {
|
||||
LOGE("received invalid metadata");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("==============Audio Metadata=============\n");
|
||||
|
||||
while (buflen >= 8) {
|
||||
dmap_code = metadata;
|
||||
if (strlen(dmap_code) != 4) {
|
||||
LOGE("received metadata with invalid DMAP code [%s]", dmap_code);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
dmap_len = (const unsigned char *) (metadata + 7);
|
||||
metadata += 8;
|
||||
buflen -= 8;
|
||||
datalen = 0;
|
||||
while (datalen < buflen && (datalen + 8 > buflen || memcmp(metadata + datalen + 4, mark, 3) != 0)) {
|
||||
datalen++;
|
||||
}
|
||||
process_metadata (count, dmap_code, dmap_len, metadata, datalen);
|
||||
metadata += datalen;
|
||||
buflen -= datalen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user