Browse Source

Validate capture format and diagnose capture thread failures

master
evgeny 2 days ago
parent
commit
5092bdf9fe
  1. 14
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt
  2. 20
      tools/chatgui-android/libutun_lite/voice_recorder.c

14
tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt

@ -82,8 +82,14 @@ class AudioRecorderManager {
var totalRead = 0L
while (isRecording && device.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
val read = device.read(buffer, 0, FRAME_SAMPLES)
if (read <= 0) break
val read = try { device.read(buffer, 0, FRAME_SAMPLES) } catch (e: Exception) {
if (isRecording) LogManager.addLog("ERROR", "AudioRecorder", "capture read failed: ${e.message}")
break
}
if (read <= 0) {
if (isRecording) LogManager.addLog("ERROR", "AudioRecorder", "capture read failed code=$read")
break
}
NativeLib.voiceFeed(buffer.copyOf(read))
totalRead += read
}
@ -101,7 +107,7 @@ class AudioRecorderManager {
isRecording = false
audioRecord?.apply {
try { stop() } catch (_: Exception) {}
try { stop() } catch (e: Exception) { LogManager.addLog("WARN", "AudioRecorder", "capture stop failed: ${e.message}") }
}
recordingThread?.join()
recordingThread = null
@ -118,7 +124,7 @@ class AudioRecorderManager {
isRecording = false
audioRecord?.apply {
try { stop() } catch (_: Exception) {}
try { stop() } catch (e: Exception) { LogManager.addLog("WARN", "AudioRecorder", "capture cancel failed: ${e.message}") }
}
recordingThread?.join()
recordingThread = null

20
tools/chatgui-android/libutun_lite/voice_recorder.c

@ -40,9 +40,6 @@ struct voice_recorder {
int preset;
float peak_level;
float waveform_levels[100];
int waveform_count;
int64_t next_wf_time_ms;
int64_t start_time_ms;
};
@ -110,6 +107,10 @@ void voice_recorder_deinit(void) {
}
int voice_recorder_start(const char* channel_id, int sample_rate, int channels) {
if (!channel_id || !channel_id[0] || strlen(channel_id) >= 64 || sample_rate != 48000 || channels != 1) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice start: invalid target or capture format rate=%d channels=%d", sample_rate, channels);
return -1;
}
pthread_mutex_lock(&g_init_mtx);
if (!g_rec) {
DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "voice_recorder_start: not initialized (g_rec=NULL)");
@ -124,8 +125,6 @@ int voice_recorder_start(const char* channel_id, int sample_rate, int channels)
return -1;
}
if (sample_rate <= 0) sample_rate = 48000;
if (channels <= 0) channels = 1;
g_rec->sample_rate = sample_rate;
g_rec->channels = channels;
g_rec->frame_samples = sample_rate * FRAME_MS / 1000;
@ -133,8 +132,6 @@ int voice_recorder_start(const char* channel_id, int sample_rate, int channels)
g_rec->pcm_count = 0;
g_rec->active = 1;
g_rec->waveform_count = 0;
g_rec->next_wf_time_ms = 0;
struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
g_rec->start_time_ms = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
@ -165,14 +162,6 @@ int voice_recorder_feed(const int16_t* samples, int count) {
sum_sq += v * v; float av = fabsf(v); if (av > peak) peak = av;
}
g_rec->peak_level = (sqrtf(sum_sq / (float)count) * 2.0f + peak) / 2.0f;
/* accumulate waveform level every ~100ms */
{ int64_t now = now_ms();
if (g_rec->waveform_count < 100 && now >= g_rec->next_wf_time_ms) {
g_rec->waveform_levels[g_rec->waveform_count++] = g_rec->peak_level;
g_rec->next_wf_time_ms = now + 100;
}
}
}
if (g_rec->compressor && g_rec->compressor_enabled) {
@ -228,6 +217,7 @@ int voice_recorder_stop(int* out_duration_ms) {
if (g_rec->compressor && g_rec->compressor_enabled) {
struct audio_compressor* replacement = audio_compressor_clone_config(g_rec->compressor);
if (!replacement) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "voice stop: replacement compressor allocation failed");
u_free(req); u_free(post); voice_cleanup_locked(g_rec);
pthread_mutex_unlock(&g_rec->mtx); pthread_mutex_unlock(&g_init_mtx); return -1;
}

Loading…
Cancel
Save