/* main loop or GStreamer streaming thread */ static void schedule_frame(SpiceGstDecoder *decoder) { guint32 now = stream_get_time(decoder->base.stream); g_mutex_lock(&decoder->queues_mutex); while (!decoder->timer_id) { SpiceGstFrame *gstframe = g_queue_peek_head(decoder->display_queue); if (!gstframe) { break; } if (now < gstframe->frame->mm_time) { decoder->timer_id = g_timeout_add(gstframe->frame->mm_time - now, display_frame, decoder); } else if (g_queue_get_length(decoder->display_queue) == 1) { /* Still attempt to display the least out of date frame so the * video is not completely frozen for an extended period of time. */ decoder->timer_id = g_timeout_add(0, display_frame, decoder); } else { SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping", __FUNCTION__, now - gstframe->frame->mm_time, gstframe->frame->mm_time, now); stream_dropped_frame_on_playback(decoder->base.stream); g_queue_pop_head(decoder->display_queue); free_gst_frame(gstframe); } } g_mutex_unlock(&decoder->queues_mutex); }
static void mjpeg_decoder_schedule(MJpegDecoder *decoder) { if (decoder->timer_id) { return; } guint32 time = stream_get_time(decoder->base.stream); SpiceFrame *frame = decoder->cur_frame; decoder->cur_frame = NULL; do { if (frame) { if (spice_mmtime_diff(time, frame->mm_time) <= 0) { guint32 d = frame->mm_time - time; decoder->cur_frame = frame; decoder->timer_id = g_timeout_add(d, mjpeg_decoder_decode_frame, decoder); break; } SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping ", __FUNCTION__, time - frame->mm_time, frame->mm_time, time); stream_dropped_frame_on_playback(decoder->base.stream); free_spice_frame(frame); } frame = g_queue_pop_head(decoder->msgq); } while (frame); }
void speaker_level_w(running_device *device, int new_level) { speaker_state *sp = get_safe_token(device); int volume; attotime time; if (new_level == sp->level) return; if (new_level < 0) new_level = 0; else if (new_level >= sp->num_levels) new_level = sp->num_levels - 1; volume = sp->levels[sp->level]; time = timer_get_time(device->machine); if (attotime_compare(time, sp->channel_next_sample_time) < 0) { /* Stream sample is yet unfinished, but we may have one or more interm. samples */ update_interm_samples(sp, time, volume); /* Do not forget to update speaker state before returning! */ sp->level = new_level; return; } /* Reaching here means such time has passed since last stream update * that we can add at least one complete sample to the stream. * The details have to be handled by speaker_sound_update() */ /* Force streams.c to update sound until this point in time now */ stream_update(sp->channel); /* This is redundant because time update has to be done within speaker_sound_update() anyway, * however this ensures synchronization between the speaker and stream timing: */ sp->channel_last_sample_time = stream_get_time(sp->channel); sp->channel_next_sample_time = attotime_add_attoseconds(sp->channel_last_sample_time, sp->channel_sample_period); sp->next_interm_sample_time = attotime_add_attoseconds(sp->channel_last_sample_time, sp->interm_sample_period); sp->last_update_time = sp->channel_last_sample_time; /* Assertion: time - last_update_time < channel_sample_period, i.e. time < channel_next_sample_time */ /* The overshooting fraction of time will make zero, one or more interm. samples: */ update_interm_samples(sp, time, volume); /* Finally update speaker state before returning */ sp->level = new_level; } /* speaker_level_w */
static DEVICE_START( speaker ) { speaker_state *sp = get_safe_token(device); const speaker_interface *intf = (const speaker_interface *) device->baseconfig().static_config; int i; double x; sp->channel = stream_create(device, 0, 1, device->machine->sample_rate, sp, speaker_sound_update); if (intf != NULL) { assert(intf->num_level > 1); assert(intf->levels != NULL); sp->num_levels = intf->num_level; sp->levels = intf->levels; } else { sp->num_levels = 2; sp->levels = default_levels; } sp->level = 0; for (i = 0; i < FILTER_LENGTH; i++) sp->composed_volume[i] = 0; sp->composed_sample_index = 0; sp->last_update_time = timer_get_time(device->machine); sp->channel_sample_period = HZ_TO_ATTOSECONDS(device->machine->sample_rate); sp->channel_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(sp->channel_sample_period); sp->interm_sample_period = sp->channel_sample_period / RATE_MULTIPLIER; sp->interm_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(sp->interm_sample_period); sp->channel_last_sample_time = stream_get_time(sp->channel); sp->channel_next_sample_time = attotime_add_attoseconds(sp->channel_last_sample_time, sp->channel_sample_period); sp->next_interm_sample_time = attotime_add_attoseconds(sp->channel_last_sample_time, sp->interm_sample_period); sp->interm_sample_index = 0; /* Note: To avoid time drift due to floating point inaccuracies, * it is good if the speaker time synchronizes itself with the stream timing regularly. */ /* Compute filter kernel; */ /* (Done for each device though the data is shared... * No problem really, but should be done as part of system init if I knew how) */ #if 1 /* This is an approximated sinc (a perfect sinc makes an ideal low-pass filter). * FILTER_STEP determines the cutoff frequency, * which should be below the Nyquist freq, i.e. half the sample rate. * Smaller step => kernel extends in time domain => lower cutoff freq * In this case, with sinc, filter step PI corresponds to the Nyq. freq. * Since we do not get a perfect filter => must lower the cutoff freq some more. * For example, step PI/(2*RATE_MULTIPLIER) corresponds to cutoff freq = sample rate / 4; * With -samplerate 48000, cutoff freq is ca 12kHz while the Nyq. freq is 24kHz. * With -samplerate 96000, cutoff freq is ca 24kHz while the Nyq. freq is 48kHz. * For a steeper, more efficient filter, increase FILTER_LENGTH at the expense of CPU usage. */ #define FILTER_STEP (M_PI / 2 / RATE_MULTIPLIER) /* Distribute symmetrically on x axis; center has x=0 if length is odd */ for (i = 0, x = (0.5 - FILTER_LENGTH / 2.) * FILTER_STEP; i < FILTER_LENGTH; i++, x += FILTER_STEP) { if (x == 0) ampl[i] = 1; else ampl[i] = sin(x) / x; } #else /* Trivial average filter with poor frequency cutoff properties; * First zero (frequency where amplification=0) = sample rate / filter length * Cutoff frequency approx <= first zero / 2 */ for (i = 0, i < FILTER_LENGTH; i++) ampl[i] = 1; #endif }