void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; }
++
++//assuming pthread cancellation is disabled
int open_mixer() {
int response = 0;
if (hardware_mixer) {
return response;
}
++//assuming pthread cancellation is disabled
void close_mixer() {
if (alsa_mix_handle) {
snd_mixer_close(alsa_mix_handle);
}
}
++//assuming pthread cancellation is disabled
void do_snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *mix_elem, double vol) {
if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, 0) != 0) {
debug(1, "Can't set playback volume accurately to %f dB.", vol);
}
static int init(int argc, char **argv) {
++ // for debugging
+ snd_output_stdio_attach(&output, stdout, 0);
+
// debug(2,"audio_alsa init called.");
int response = 0; // this will be what we return to the caller.
const char *str;
warn("Invalid audio argument: \"%s\" -- ignored", argv[optind]);
}
- debug(1, "alsa output device name is \"%s\".", alsa_out_dev);
+ debug(1, "alsa: output device name is \"%s\".", alsa_out_dev);
if (hardware_mixer) {
+ int oldState;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable
if (alsa_mix_dev == NULL)
alsa_mix_dev = alsa_out_dev;
}
debug_mutex_unlock(&alsa_mutex, 3); // release the mutex
pthread_cleanup_pop(0);
+ pthread_setcancelstate(oldState, NULL);
} else {
- // debug(1, "Has no mixer and thus no hardware mute.");
+ debug(1, "alsa: no hardware mixer selected.");
}
alsa_mix_handle = NULL;
stop();
}
-int open_alsa_device(void) {
++//assuming pthread cancellation is disabled
+int actual_open_alsa_device(void) {
// the alsa mutex is already acquired when this is called
const snd_pcm_uframes_t minimal_buffer_headroom =
352 * 2; // we accept this much headroom in the hardware buffer, but we'll
measurement_data_is_valid = 0;
}
++//assuming pthread cancellation is disabled
+int my_snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) {
+ int ret;
+ snd_pcm_status_t *alsa_snd_pcm_status;
+ snd_pcm_status_alloca(&alsa_snd_pcm_status);
+
+ struct timespec tn; // time now
+ snd_htimestamp_t update_timestamp; // actually a struct timespec
+
+ ret = snd_pcm_status(pcm, alsa_snd_pcm_status);
+ if (ret) {
+ *delayp = 0;
+ return ret;
+ }
+
+ snd_pcm_state_t state = snd_pcm_status_get_state(alsa_snd_pcm_status);
+ if (state != SND_PCM_STATE_RUNNING) {
+ *delayp = 0;
+ return -EIO; // might be a better code than this...
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &tn);
+ snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp);
+
+ uint64_t t1 = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec;
+ uint64_t t2 = update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec;
+ uint64_t delta = t1 - t2;
+
+ uint64_t frames_played_since_last_interrupt =
+ ((uint64_t)desired_sample_rate * delta) / 1000000000;
+ snd_pcm_sframes_t frames_played_since_last_interrupt_sized = frames_played_since_last_interrupt;
+
+ *delayp =
+ snd_pcm_status_get_delay(alsa_snd_pcm_status) - frames_played_since_last_interrupt_sized;
+ return 0;
+}
+
int delay(long *the_delay) {
// snd_pcm_sframes_t is a signed long -- hence the return of a "long"
int reply = 0;
frame_index = 0;
measurement_data_is_valid = 0;
}
- debug_mutex_unlock(&alsa_mutex, 3);
+ debug_mutex_unlock(&alsa_mutex, 0);
pthread_cleanup_pop(0); // release the mutex
}
+ pthread_setcancelstate(oldState, NULL);
return ret;
}
close_mixer();
}
}
-- mute_request_pending = 0;
-
++ mute_request_pending = 0;
+ pthread_setcancelstate(oldState, NULL);
}