-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaudio_sdl.c
117 lines (93 loc) · 2.86 KB
/
audio_sdl.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <SDL/SDL_audio.h>
#include <unistd.h>
#include <assert.h>
#include "audio.h"
#include "memory.h"
#define NUM_SAMPLES 2048
char * audio_pre_buffer;
CircularBuffer audio_buffer;
pthread_t audio_thread;
pthread_mutex_t audio_mutex;
int buffer_samples_can_write() {
int result;
pthread_mutex_lock(&audio_mutex);
result = circularbuffer_bytes_writable(audio_buffer);
pthread_mutex_unlock(&audio_mutex);
return result / 2;
}
void* audio_exec(void* udata) {
float buffer_time_us = (float)(1e6 * NUM_SAMPLES) / SAMPLE_FREQ;
int sample_thresh = NUM_SAMPLES / 2;
while(1) {
// wait till we can write a good chunk
int nsamples;
while((nsamples = buffer_samples_can_write()) < sample_thresh) {
usleep(buffer_time_us / 4);
}
// compute the audio that we know we need
audio_fill_buffer((int16_t*)audio_pre_buffer, nsamples);
// now lock the circular buffer and copy
pthread_mutex_lock(&audio_mutex);
int s1, s2;
char *b1, *b2;
int nbytes = nsamples * 2;
circularbuffer_write_buffers(audio_buffer, &b1, &s1, &b2, &s2,
nbytes);
int to_write = MIN(nbytes, s1);
memcpy(b1, audio_pre_buffer, to_write);
nbytes -= to_write;
if(nbytes > 0) {
to_write = MIN(nbytes, s2);
memcpy(b2, &audio_pre_buffer[s1], to_write);
}
pthread_mutex_unlock(&audio_mutex);
// don't immediately bang on the lock
usleep(buffer_time_us / 4);
}
}
void fill_audio(void *udata, Uint8 *stream, int len) {
int nwords = len / 2;
int s1, s2;
char *b1, *b2;
pthread_mutex_lock(&audio_mutex);
circularbuffer_read_buffers(audio_buffer, &b1, &s1, &b2, &s2,
len);
int tocopy = MIN(len, s1);
memcpy(stream, b1, tocopy);
len -= tocopy;
if(len > 0) {
tocopy = MIN(len, s2);
memcpy(stream, b2, tocopy);
len -= tocopy;
}
pthread_mutex_unlock(&audio_mutex);
}
/*
void fill_audio(void *udata, Uint8 *stream, int len) {
audio_fill_buffer((int16_t*)stream, len / 2);
}
*/
void native_audio_init() {
// twice the number of samples in the sdl buffer (2 bytes per
// channel per sample)
int buffer_size = NUM_SAMPLES * 2 * 2 * 2;
audio_buffer = circularbuffer_make(buffer_size);
audio_pre_buffer = malloc(buffer_size);
pthread_mutex_init(&audio_mutex, NULL);
pthread_create(&audio_thread, NULL, audio_exec, NULL);
SDL_AudioSpec wanted;
// Set the audio format
wanted.freq = SAMPLE_FREQ;
wanted.format = AUDIO_S16SYS;
wanted.channels = 2; // 1 = mono, 2 = stereo
wanted.samples = NUM_SAMPLES; // Good low-latency value for callback
wanted.padding = 0;
wanted.callback = fill_audio;
wanted.userdata = NULL;
// Open the audio device, forcing the desired format
if ( SDL_OpenAudio(&wanted, NULL) < 0 ) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
exit(-1);
}
SDL_PauseAudio(0);
}