/* 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);
}
Exemple #3
0
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 */
Exemple #4
0
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
}