2024-10-13 22:43:33 +08:00
|
|
|
#include "audio.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
2024-10-15 01:36:02 +08:00
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
|
2024-10-13 22:43:33 +08:00
|
|
|
static SDL_AudioSpec recording_spec;
|
|
|
|
static SDL_AudioSpec playback_spec;
|
|
|
|
static SDL_AudioSpec received_recording_spec;
|
|
|
|
static SDL_AudioSpec received_playback_spec;
|
|
|
|
|
|
|
|
int audio_init(audio_state* state)
|
|
|
|
{
|
|
|
|
state->recording_device_id = 0;
|
|
|
|
state->playback_device_id = 0;
|
|
|
|
|
|
|
|
SDL_zero(recording_spec);
|
|
|
|
recording_spec.freq = 44100;
|
|
|
|
recording_spec.format = AUDIO_S16;
|
|
|
|
recording_spec.channels = 2;
|
|
|
|
recording_spec.samples = 4096;
|
|
|
|
recording_spec.callback = audio_recording_callback;
|
|
|
|
recording_spec.userdata = state;
|
|
|
|
|
|
|
|
SDL_zero(playback_spec);
|
|
|
|
playback_spec.freq = 44100;
|
|
|
|
playback_spec.format = AUDIO_S16;
|
|
|
|
playback_spec.channels = 2;
|
|
|
|
playback_spec.samples = 4096;
|
|
|
|
playback_spec.callback = audio_playback_callback;
|
|
|
|
playback_spec.userdata = state;
|
|
|
|
|
|
|
|
state->recording_buffer = NULL;
|
|
|
|
state->recording_buffer_size = 0;
|
|
|
|
state->recording_buffer_position = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_recording_init(audio_state* state, int index)
|
|
|
|
{
|
|
|
|
SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(index, 1), 1, &recording_spec, &received_recording_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
|
2024-10-15 01:36:02 +08:00
|
|
|
log_message(LOG_INFO, "Recording Device: %s", SDL_GetAudioDeviceName(index, 1));
|
2024-10-13 22:43:33 +08:00
|
|
|
if (!device_id) {
|
2024-10-15 01:36:02 +08:00
|
|
|
log_message(LOG_INFO, "Failed to open recording device! SDL Error: %s", SDL_GetError());
|
2024-10-13 22:43:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
state->recording_device_id = device_id;
|
|
|
|
|
|
|
|
unsigned int bytes_per_sample = received_recording_spec.channels * (SDL_AUDIO_BITSIZE(received_recording_spec.format)/8);
|
|
|
|
unsigned int bytes_per_second = received_recording_spec.freq * bytes_per_sample;
|
|
|
|
state->recording_buffer_size = MAX_RECORDING_SECONDS * bytes_per_second;
|
|
|
|
|
|
|
|
if (state->recording_buffer) free(state->recording_buffer);
|
|
|
|
state->recording_buffer = malloc(state->recording_buffer_size);
|
|
|
|
memset(state->recording_buffer, 0, state->recording_buffer_size);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_destroy(audio_state* state)
|
|
|
|
{
|
|
|
|
free(state->recording_buffer);
|
|
|
|
SDL_CloseAudioDevice(state->recording_device_id);
|
|
|
|
SDL_CloseAudioDevice(state->playback_device_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int audio_playback_init(audio_state* state)
|
|
|
|
{
|
|
|
|
if (!state->recording_buffer) {
|
2024-10-15 01:36:02 +08:00
|
|
|
log_message(LOG_INFO, "Audio buffer not initialized");
|
2024-10-13 22:43:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_AudioDeviceID device_id = SDL_OpenAudioDevice(NULL, 0, &playback_spec, &received_playback_spec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
|
|
|
|
if (!device_id) {
|
2024-10-15 01:36:02 +08:00
|
|
|
log_message(LOG_INFO, "Failed to open playback device! SDL Error: %s", SDL_GetError());
|
2024-10-13 22:43:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
state->playback_device_id = device_id;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-10-15 01:36:02 +08:00
|
|
|
void audio_recording_callback(void* userdata, uint8_t* stream, int len)
|
2024-10-13 22:43:33 +08:00
|
|
|
{
|
|
|
|
audio_state* state = userdata;
|
|
|
|
|
|
|
|
int space_left = state->recording_buffer_size - state->recording_buffer_position;
|
|
|
|
if (space_left <= 0) {
|
2024-10-17 03:16:41 +08:00
|
|
|
log_message(LOG_INFO, "Stopping recording ID: %i", state->recording_device_id);
|
2024-10-13 22:43:33 +08:00
|
|
|
SDL_PauseAudioDevice(state->recording_device_id, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > space_left) {
|
|
|
|
len = space_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&state->recording_buffer[state->recording_buffer_position], stream, len);
|
|
|
|
state->recording_buffer_position += len;
|
|
|
|
|
2024-10-17 03:16:41 +08:00
|
|
|
log_message(LOG_INFO, "Record pos: %u/%u (%u)", state->recording_buffer_position, state->recording_buffer_size, len);
|
2024-10-13 22:43:33 +08:00
|
|
|
}
|
|
|
|
|
2024-10-15 01:36:02 +08:00
|
|
|
void audio_playback_callback(void* userdata, uint8_t* stream, int len)
|
2024-10-13 22:43:33 +08:00
|
|
|
{
|
|
|
|
audio_state* state = userdata;
|
|
|
|
|
|
|
|
int space_left = state->recording_buffer_size - state->recording_buffer_position;
|
|
|
|
if (space_left <= 0) {
|
2024-10-17 03:16:41 +08:00
|
|
|
log_message(LOG_INFO, "Stopping playback ID: %i", state->recording_device_id);
|
2024-10-13 22:43:33 +08:00
|
|
|
SDL_PauseAudioDevice(state->playback_device_id, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > space_left) {
|
|
|
|
len = space_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(stream, &state->recording_buffer[state->recording_buffer_position], len);
|
|
|
|
state->recording_buffer_position += len;
|
|
|
|
|
2024-10-17 03:16:41 +08:00
|
|
|
log_message(LOG_INFO, "Playback pos: %u/%u (%u)", state->recording_buffer_position, state->recording_buffer_size, len);
|
2024-10-13 22:43:33 +08:00
|
|
|
}
|