Skip to content

Commit 5615521

Browse files
committed
finalized microphone implementation
1 parent d5d7399 commit 5615521

File tree

6 files changed

+177
-88
lines changed

6 files changed

+177
-88
lines changed

lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ if (VANILLA_BUILD_TESTS)
3232
target_include_directories(${TEST_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
3333
endfunction()
3434

35+
add_test(audioheader "test/audioheader.c")
3536
add_test(bittest "test/bittest.c")
3637
add_test(reversebittest "test/reversebit.c")
3738
add_test(reversebitstresstest "test/reversebitstresstest.c")

lib/gamepad/audio.c

Lines changed: 98 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -8,123 +8,122 @@
88

99
#include <pthread.h>
1010
#include <stdint.h>
11+
#include <stdlib.h>
1112
#include <string.h>
1213
#include <sys/time.h>
14+
#include <unistd.h>
1315

1416
#include "gamepad.h"
1517
#include "vanilla.h"
1618
#include "util.h"
1719

18-
#pragma pack(push, 1)
19-
typedef struct {
20-
unsigned format : 3;
21-
unsigned mono : 1;
22-
unsigned vibrate : 1;
23-
unsigned type : 1;
24-
unsigned seq_id : 10;
25-
unsigned payload_size : 16;
26-
unsigned timestamp : 32;
27-
unsigned char payload[2048];
28-
} AudioPacket;
29-
const static unsigned int TYPE_AUDIO = 0;
30-
const static unsigned int TYPE_VIDEO = 1;
31-
#pragma pack(pop)
32-
33-
typedef struct {
34-
uint32_t timestamp;
35-
uint32_t unknown_freq_0[2];
36-
uint32_t unknown_freq_1[2];
37-
uint32_t video_format;
38-
} AudioPacketVideoFormat;
39-
40-
static unsigned char queued_audio[2048];
20+
static unsigned char queued_audio[8192];
4121
static size_t queued_audio_start = 0;
4222
static size_t queued_audio_end = 0;
4323
static pthread_mutex_t queued_audio_mutex;
24+
static pthread_cond_t queued_audio_cond;
4425

4526
int send_audio_packet(const void *data, size_t len)
4627
{
4728
pthread_mutex_lock(&queued_audio_mutex);
4829

49-
for (size_t i = 0; i < len; ) {
30+
for (size_t i = 0; i < len; ) {
5031
size_t phys = queued_audio_end % sizeof(queued_audio);
5132
size_t max_write = MIN(sizeof(queued_audio) - phys, len - i);
5233
memcpy(queued_audio + phys, ((const unsigned char *) data) + i, max_write);
34+
5335
i += max_write;
5436
queued_audio_end += max_write;
37+
38+
// Skip start ahead if necessary
39+
if (queued_audio_end > queued_audio_start + sizeof(queued_audio)) {
40+
queued_audio_start = queued_audio_end - sizeof(queued_audio);
41+
}
5542
}
5643

44+
pthread_cond_broadcast(&queued_audio_cond);
45+
5746
pthread_mutex_unlock(&queued_audio_mutex);
5847

5948
return VANILLA_SUCCESS;
6049
}
6150

62-
static void handle_queued_audio(gamepad_context_t *ctx, int seq_id)
51+
static void *handle_queued_audio(void *data)
6352
{
64-
AudioPacket ap;
53+
// Mic only ever sends 512 bytes at a time
54+
const size_t MIC_PAYLOAD_SIZE = 512;
6555

66-
// Initialize payload size to zero
67-
const size_t MIC_PAYLOAD_SIZE = 512;
68-
ap.payload_size = 0;
56+
gamepad_context_t *ctx = (gamepad_context_t *) data;
6957

70-
// Lock mutex
7158
pthread_mutex_lock(&queued_audio_mutex);
7259

73-
// If available, copy over to our packet
74-
if (queued_audio_end >= (queued_audio_start + MIC_PAYLOAD_SIZE)) {
75-
for (size_t i = 0; i < MIC_PAYLOAD_SIZE; ) {
76-
size_t phys = queued_audio_start % sizeof(queued_audio);
77-
size_t max_write = MIN(sizeof(queued_audio) - phys, MIC_PAYLOAD_SIZE - i);
78-
memcpy(ap.payload + i, queued_audio + queued_audio_start, max_write);
79-
i += max_write;
80-
queued_audio_start += max_write;
81-
}
82-
ap.payload_size = MIC_PAYLOAD_SIZE;
83-
}
60+
while (!is_interrupted()) {
61+
while (!is_interrupted() && queued_audio_end < (queued_audio_start + MIC_PAYLOAD_SIZE)) {
62+
// Wait for more data
63+
pthread_cond_wait(&queued_audio_cond, &queued_audio_mutex);
64+
}
65+
66+
if (is_interrupted()) {
67+
break;
68+
}
69+
70+
AudioPacket ap;
71+
72+
// Copy data into our packet
73+
for (size_t i = 0; i < MIC_PAYLOAD_SIZE; ) {
74+
size_t phys = queued_audio_start % sizeof(queued_audio);
75+
size_t max_write = MIN(sizeof(queued_audio) - phys, MIC_PAYLOAD_SIZE - i);
76+
memcpy(ap.payload + i, queued_audio + phys, max_write);
77+
78+
i += max_write;
79+
queued_audio_start += max_write;
80+
}
81+
82+
// Don't need access to the buffer while we set up the packet
83+
pthread_mutex_unlock(&queued_audio_mutex);
84+
85+
// Set up remaining default parameters
86+
ap.format = 6;
87+
ap.mono = 1;
88+
ap.vibrate = 0;
89+
ap.type = TYPE_AUDIO; // Audio data
90+
ap.timestamp = 0; // Gamepad actually sends no timestamp
91+
ap.payload_size = MIC_PAYLOAD_SIZE;
92+
93+
static unsigned int seq_id = 0;
94+
ap.seq_id = seq_id++;
95+
96+
// Reverse bits on params
97+
ap.format = reverse_bits(ap.format, 3);
98+
ap.seq_id = reverse_bits(ap.seq_id, 10);
99+
ap.payload_size = reverse_bits(ap.payload_size, 16);//ntohs(ap.payload_size);
100+
// ap.timestamp = reverse_bits(ap.timestamp, 32); // Not necessary because timestamp is 0
101+
102+
// Further reverse bits
103+
unsigned char *bytes = (unsigned char *) &ap;
104+
const size_t header_sz = sizeof(AudioPacket) - sizeof(ap.payload);
105+
for (int i = 0; i < 4; i++) { // 4 instead of 8 because ap.timestamp == 0
106+
bytes[i] = (unsigned char) reverse_bits(bytes[i], 8);
107+
}
108+
109+
// Console expects 512 bytes every 16 ms so make sure we achieve that interval
110+
static struct timeval last;
111+
struct timeval now;
112+
gettimeofday(&now, 0);
113+
long diff = (now.tv_sec - last.tv_sec) * 1000000 + (now.tv_usec - last.tv_usec);
114+
static const long target_delta = 16000;
115+
if (diff < target_delta) {
116+
usleep(target_delta - diff);
117+
}
118+
gettimeofday(&last, 0);
119+
120+
// Send packet to console
121+
send_to_console(ctx->socket_aud, &ap, header_sz + MIC_PAYLOAD_SIZE, PORT_AUD);
122+
123+
pthread_mutex_lock(&queued_audio_mutex);
124+
}
84125

85-
// Unlock
86126
pthread_mutex_unlock(&queued_audio_mutex);
87-
88-
// If we didn't get audio, return here
89-
if (!ap.payload_size) {
90-
return;
91-
}
92-
93-
// struct timeval tv;
94-
// gettimeofday(&tv, 0);
95-
// if ((tv.tv_sec % 2) == 1) {
96-
// for (int i = 0; i < ap.payload_size; i++) {
97-
// ap.payload[i] = (rand() % 0xFF);
98-
// }
99-
// vanilla_log("NOISE!");
100-
// } else {
101-
// memset(ap.payload, 0x00, ap.payload_size);
102-
// vanilla_log("...quiet...");
103-
// }
104-
105-
// Set up remaining default parameters
106-
ap.format = 6;
107-
ap.mono = 1;
108-
ap.vibrate = 0;
109-
ap.type = TYPE_AUDIO; // Audio data
110-
ap.seq_id = seq_id + 1;
111-
ap.timestamp = 0;
112-
113-
// Reverse bits on params
114-
ap.format = reverse_bits(ap.format, 3);
115-
ap.seq_id = reverse_bits(ap.seq_id, 10);
116-
ap.payload_size = reverse_bits(ap.payload_size, 16);//ntohs(ap.payload_size);
117-
// ap.timestamp = reverse_bits(ap.timestamp, 32); // Not necessary because timestamp is 0
118-
119-
// Further reverse bits
120-
unsigned char *bytes = (unsigned char *) &ap;
121-
const size_t header_sz = sizeof(AudioPacket) - sizeof(ap.payload);
122-
for (int i = 0; i < header_sz; i++) {
123-
bytes[i] = (unsigned char) reverse_bits(bytes[i], 8);
124-
}
125-
126-
// Send packet to console
127-
send_to_console(ctx->socket_aud, &ap, header_sz + ap.payload_size, PORT_AUD);
128127
}
129128

130129
void handle_audio_packet(gamepad_context_t *ctx, unsigned char *data, size_t len)
@@ -162,7 +161,7 @@ void handle_audio_packet(gamepad_context_t *ctx, unsigned char *data, size_t len
162161
uint8_t vibrate_val = ap->vibrate;
163162
push_event(ctx->event_loop, VANILLA_EVENT_VIBRATE, &vibrate_val, sizeof(vibrate_val));
164163

165-
handle_queued_audio(ctx, ap->seq_id);
164+
handle_queued_audio(ctx);
166165
}
167166

168167
void *listen_audio(void *x)
@@ -175,6 +174,14 @@ void *listen_audio(void *x)
175174
queued_audio_end = 0;
176175

177176
pthread_mutex_init(&queued_audio_mutex, 0);
177+
pthread_cond_init(&queued_audio_cond, 0);
178+
179+
pthread_t mic_thread;
180+
int mic_thread_created = 1;
181+
if (pthread_create(&mic_thread, 0, handle_queued_audio, info) != 0) {
182+
vanilla_log("Failed to create mic thread");
183+
mic_thread_created = 0;
184+
}
178185

179186
do {
180187
size = recv(info->socket_aud, data, sizeof(data), 0);
@@ -183,7 +190,13 @@ void *listen_audio(void *x)
183190
}
184191
} while (!is_interrupted());
185192

186-
pthread_mutex_destroy(&queued_audio_mutex);
193+
if (mic_thread_created) {
194+
pthread_cond_broadcast(&queued_audio_cond);
195+
pthread_join(mic_thread, 0);
196+
}
197+
198+
pthread_cond_destroy(&queued_audio_cond);
199+
pthread_mutex_destroy(&queued_audio_mutex);
187200

188201
pthread_exit(NULL);
189202

lib/gamepad/audio.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,31 @@
22
#define GAMEPAD_AUDIO_H
33

44
#include <stddef.h>
5+
#include <stdint.h>
6+
7+
#pragma pack(push, 1)
8+
typedef struct {
9+
unsigned format : 3;
10+
unsigned mono : 1;
11+
unsigned vibrate : 1;
12+
unsigned type : 1;
13+
unsigned seq_id : 10;
14+
unsigned payload_size : 16;
15+
unsigned timestamp : 32;
16+
unsigned char payload[2048];
17+
} AudioPacket;
18+
const static unsigned int TYPE_AUDIO = 0;
19+
const static unsigned int TYPE_VIDEO = 1;
20+
#pragma pack(pop)
21+
22+
typedef struct {
23+
uint32_t timestamp;
24+
uint32_t unknown_freq_0[2];
25+
uint32_t unknown_freq_1[2];
26+
uint32_t video_format;
27+
} AudioPacketVideoFormat;
528

629
void *listen_audio(void *x);
730
int send_audio_packet(const void *data, size_t len);
831

9-
#endif // GAMEPAD_AUDIO_H
32+
#endif // GAMEPAD_AUDIO_H

lib/gamepad/gamepad.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ void send_to_console(int fd, const void *data, size_t data_size, uint16_t port)
105105

106106
ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &addr, addr_size);
107107
if (sent == -1) {
108-
vanilla_log("Failed to send to Wii U socket: fd: %d, port: %d, errno: %i", fd, console_port, skterr());
108+
int err = skterr();
109+
if (err != 111) { // 111 is connection refused, occurs if we lose connection, but we'll already know that for other reasons so we don't need to spam the console with this error
110+
vanilla_log("Failed to send to Wii U socket: fd: %d, port: %d, errno: %i", fd, console_port, skterr());
111+
}
109112
}
110113
}
111114

lib/test/audioheader.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <stdint.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include "gamepad/audio.h"
6+
#include "util.h"
7+
8+
int main(int argc, const char **argv)
9+
{
10+
if (argc != 2) {
11+
printf("Usage: %s <hex-string>\n", argv[0]);
12+
return 1;
13+
}
14+
15+
const char *s = argv[1];
16+
uint8_t bytes[8];
17+
if (strlen(s) != sizeof(bytes) * 2) {
18+
printf("ERROR: Invalid hex data\n");
19+
return 1;
20+
}
21+
22+
char tmp_hex[3];
23+
tmp_hex[2] = 0;
24+
for (size_t i = 0; i < sizeof(bytes); i++) {
25+
memcpy(tmp_hex, s + i * 2, 2);
26+
bytes[i] = strtol(tmp_hex, 0, 16);
27+
}
28+
29+
for (int i = 0; i < sizeof(bytes); i++) {
30+
bytes[i] = (unsigned char) reverse_bits(bytes[i], 8);
31+
}
32+
33+
AudioPacket *ap = (AudioPacket *) bytes;
34+
35+
ap->format = reverse_bits(ap->format, 3);
36+
ap->seq_id = reverse_bits(ap->seq_id, 10);
37+
ap->payload_size = reverse_bits(ap->payload_size, 16);//ntohs(ap->payload_size);
38+
ap->timestamp = reverse_bits(ap->timestamp, 32);
39+
40+
printf("Format: %u\n", ap->format);
41+
printf("Mono: %u\n", ap->mono);
42+
printf("Vibrate: %u\n", ap->vibrate);
43+
printf("Type: %u\n", ap->type);
44+
printf("Seq ID: %u\n", ap->seq_id);
45+
printf("Payload Size: %u\n", ap->payload_size);
46+
printf("Timestamp: %u\n", ap->timestamp);
47+
48+
return 0;
49+
}

pipe/linux/wpa.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ void *sync_with_console_internal(void *data)
876876
nlprint("CRED RECV: %.*s", buf_len, buf);
877877
}
878878

879-
if (!memcmp("<3>WPS-CRED-RECEIVED", buf, 20)) {
879+
if (strstr(buf, "WPS-SUCCESS")) {
880880
nlprint("RECEIVED AUTHENTICATION FROM CONSOLE");
881881
cred_received = 1;
882882
break;

0 commit comments

Comments
 (0)