Exemple #1
0
int audio_capture_data(audio_capture_t audio_capture,
		       void *data, size_t size)
{
	glc_message_header_t msg_hdr;
	glc_audio_data_header_t audio_hdr;

	int ret;
	if (!(audio_capture->flags & AUDIO_CAPTURE_CAPTURING))
		return 0;

	if (audio_capture->flags & AUDIO_CAPTURE_CFG_CHANGED) {
		if ((ret = audio_capture_write_cfg(audio_capture)))
			return ret;
		audio_capture->flags &= ~AUDIO_CAPTURE_CFG_CHANGED;
	}

	if (!(audio_capture->flags & AUDIO_CAPTURE_IGNORE_TIME))
		audio_capture->time = glc_state_time(audio_capture->glc);

	msg_hdr.type = GLC_MESSAGE_AUDIO_DATA;
	audio_hdr.id = audio_capture->id; /* should be set to valid one */
	audio_hdr.size = size;
	audio_hdr.time = audio_capture->time;

	if (audio_capture->flags & AUDIO_CAPTURE_IGNORE_TIME)
		audio_capture->time += ((glc_utime_t) size * (glc_utime_t) 1000000) /
					(glc_utime_t) (audio_capture_frames_to_bytes(audio_capture, 1) *
						       audio_capture->rate);

	if ((ret = ps_packet_open(&audio_capture->packet, PS_PACKET_WRITE)))
		goto err;
	if ((ret = ps_packet_write(&audio_capture->packet,
				   &msg_hdr, sizeof(glc_message_header_t))))
		goto err;
	if ((ret = ps_packet_write(&audio_capture->packet,
				   &audio_hdr, sizeof(glc_audio_data_header_t))))
		goto err;
	if ((ret = ps_packet_write(&audio_capture->packet,
				   data, size)))
		goto err;
	if ((ret = ps_packet_close(&audio_capture->packet)))
		goto err;

	return 0;
err:
	ps_buffer_cancel(audio_capture->target);
	glc_state_set(audio_capture->glc, GLC_STATE_CANCEL);
	glc_log(audio_capture->glc, GLC_ERROR, "audio_capture",
		"can't write audio data to buffer");
	glc_log(audio_capture->glc, GLC_ERROR, "audio_capture",
		"%s (%d)", strerror(ret), ret);
	return ret;
}
Exemple #2
0
/*
 * Might be called from signal handlers.
 */
int alsa_hook_writen(alsa_hook_t alsa_hook, snd_pcm_t *pcm,
		     void **bufs, snd_pcm_uframes_t size)
{
	struct alsa_hook_stream_s *stream;
	int c, ret = 0;
	int savedErrno = errno;

	if (!(alsa_hook->flags & ALSA_HOOK_CAPTURING))
		goto leave;

	alsa_hook_get_stream(alsa_hook, pcm, &stream);

	if (unlikely(!stream->initialized)) {
		ret = EINVAL;
		goto leave;
	}

	if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream))))
		goto leave;

	if (unlikely(stream->flags & GLC_AUDIO_INTERLEAVED)) {
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_ERROR, "alsa_hook",
				 "stream format (interleaved) incompatible with snd_pcm_writen()");
		ret = EINVAL;
		goto unlock;
	}

	if (unlikely((ret = alsa_hook_wait_for_thread(alsa_hook, stream))))
		goto unlock;

	if (unlikely((ret = alsa_hook_set_data_size(stream,
				snd_pcm_frames_to_bytes(pcm, size)))))
		goto unlock;

	stream->capture_time = glc_state_time(alsa_hook->glc);
	for (c = 0; c < stream->channels; c++)
		memcpy(&stream->capture_data[c * snd_pcm_samples_to_bytes(pcm, size)], bufs[c],
		       snd_pcm_samples_to_bytes(pcm, size));

	sem_post(&stream->capture_full);

unlock:
	alsa_hook_unlock_write(alsa_hook, stream);
leave:
	errno = savedErrno;
	return ret;
}
Exemple #3
0
/*
 * Might be called from signal handlers.
 */
int alsa_hook_writei(alsa_hook_t alsa_hook, snd_pcm_t *pcm,
		     const void *buffer, snd_pcm_uframes_t size)
{
	struct alsa_hook_stream_s *stream;
	int ret = 0;
	int savedErrno = errno;

	if (!(alsa_hook->flags & ALSA_HOOK_CAPTURING))
		goto leave;

	alsa_hook_get_stream(alsa_hook, pcm, &stream);

	if (unlikely(!stream->initialized)) {
		ret = EINVAL;
		goto leave;
	}

	if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream))))
		goto leave;

	if (unlikely((ret = alsa_hook_wait_for_thread(alsa_hook, stream))))
		goto unlock;

	if (unlikely((ret = alsa_hook_set_data_size(stream,
				snd_pcm_frames_to_bytes(pcm, size)))))
		goto unlock;

	stream->capture_time = glc_state_time(alsa_hook->glc);
	memcpy(stream->capture_data, buffer, stream->capture_size);
	sem_post(&stream->capture_full);

unlock:
	alsa_hook_unlock_write(alsa_hook, stream);
leave:
	errno = savedErrno;
	return ret;
}
Exemple #4
0
/*
 * multithreading notes:
 *
 * This function could be accessed concurrently for different video streams, with
 * the pair dpy,drawable identifying each stream.
 */
int gl_capture_frame(gl_capture_t gl_capture, Display *dpy, GLXDrawable drawable)
{
	struct gl_capture_video_stream_s *video;
	glc_message_header_t msg;
	glc_video_frame_header_t pic;
	glc_utime_t now;
	glc_utime_t before_capture,after_capture;
	char *dma;
	int ret = 0;

	if (!(gl_capture->flags & GL_CAPTURE_CAPTURING))
		return 0; /* capturing not active */

	gl_capture_get_video_stream(gl_capture, &video, dpy, drawable);

	/* get current time */
	if (unlikely(gl_capture->flags & GL_CAPTURE_IGNORE_TIME))
		now = video->last + gl_capture->fps;
	else
		now = glc_state_time(gl_capture->glc);

	/* has gl_capture->fps nanoseconds elapsed since last capture */
	if ((now - video->last < gl_capture->fps) &&
	    !(gl_capture->flags & GL_CAPTURE_LOCK_FPS) &&
	    !(gl_capture->flags & GL_CAPTURE_IGNORE_TIME))
		goto finish;

	/* not really needed until now */
	gl_capture_update_video_stream(gl_capture, video);

	/* if PBO is not active, just start transfer and finish */
	if (unlikely((gl_capture->flags & GL_CAPTURE_USE_PBO) &&
	     __sync_bool_compare_and_swap(&video->pbo_active,0,1))) {
		ret = gl_capture_start_pbo(gl_capture, video);
		video->pbo_time = now;
		goto finish;
	}

	if (unlikely(ps_packet_open(&video->packet,
				((gl_capture->flags & GL_CAPTURE_LOCK_FPS) ||
				(gl_capture->flags & GL_CAPTURE_IGNORE_TIME)) ?
				(PS_PACKET_WRITE) :
				(PS_PACKET_WRITE | PS_PACKET_TRY))))
		goto finish;

	if (unlikely((ret = ps_packet_setsize(&video->packet, video->row * video->ch
						+ sizeof(glc_message_header_t)
						+ sizeof(glc_video_frame_header_t)))))
		goto cancel;

	msg.type = GLC_MESSAGE_VIDEO_FRAME;
	if (unlikely((ret = ps_packet_write(&video->packet,
					    &msg, sizeof(glc_message_header_t)))))
		goto cancel;

	/*
	 * if we are using PBO we will actually write previous picture to buffer.
	 * Also, make sure that pbo_time is not in the future. This could happen if
	 * the state time is reset by reloading the capture between a pbo start
	 * and a pbo read.
	 */
	pic.time = (gl_capture->flags & GL_CAPTURE_USE_PBO &&
		    video->pbo_time < now)?video->pbo_time:now;
	pic.id   = video->id;
	if (unlikely((ret = ps_packet_write(&video->packet,
					    &pic, sizeof(glc_video_frame_header_t)))))
		goto cancel;

	if (video->gather_stats)
		before_capture = glc_state_time(gl_capture->glc);
	if (gl_capture->flags & GL_CAPTURE_USE_PBO) {
		if (unlikely((ret = gl_capture_read_pbo(gl_capture, video))))
			goto cancel;

		ret = gl_capture_start_pbo(gl_capture, video);
		video->pbo_time = now;
	} else {
		if (unlikely((ret = ps_packet_dma(&video->packet, (void *) &dma,
					video->row * video->ch, PS_ACCEPT_FAKE_DMA))))
			goto cancel;

		ret = gl_capture_get_pixels(gl_capture, video, dma);
	}
	if (video->gather_stats) {
		after_capture = glc_state_time(gl_capture->glc);
		video->capture_time_ns += after_capture - before_capture;
	}

	ps_packet_close(&video->packet);
	video->num_frames++;
	now = glc_state_time(gl_capture->glc);

	if (unlikely((gl_capture->flags & GL_CAPTURE_LOCK_FPS) &&
		    !(gl_capture->flags & GL_CAPTURE_IGNORE_TIME))) {
		if (now - video->last < gl_capture->fps) {
			struct timespec ts = { .tv_sec  = (gl_capture->fps + video->last - now)/1000000000,
					       .tv_nsec = (gl_capture->fps + video->last - now)%1000000000 };
			nanosleep(&ts,NULL);
		}
	}

	/* increment by 1/fps seconds */
	video->last += gl_capture->fps;

finish:
	if (unlikely(ret != 0))
		gl_capture_error(gl_capture, ret);

	if (gl_capture->flags & GL_CAPTURE_DRAW_INDICATOR)
		glCallList(video->indicator_list);

	return ret;
cancel:
	if (ret == EBUSY) {
		ret = 0;
		glc_log(gl_capture->glc, GLC_INFO, "gl_capture",
			 "dropped frame, buffer not ready");
	}
	ps_packet_cancel(&video->packet);
	goto finish;
}

int gl_capture_refresh_color_correction(gl_capture_t gl_capture)
{
	struct gl_capture_video_stream_s *video;

	if (unlikely(!(gl_capture->flags & GL_CAPTURE_CAPTURING)))
		return 0; /* capturing not active */

	glc_log(gl_capture->glc, GLC_INFO, "gl_capture",
		 "refreshing color correction");

	pthread_rwlock_rdlock(&gl_capture->videolist_lock);
	video = gl_capture->video;
	while (video != NULL) {
		gl_capture_update_color(gl_capture, video);
		video = video->next;
	}
	pthread_rwlock_unlock(&gl_capture->videolist_lock);

	return 0;
}

/** \todo support GammaRamp */
int gl_capture_update_color(gl_capture_t gl_capture, struct gl_capture_video_stream_s *video)
{
	glc_message_header_t msg_hdr;
	glc_color_message_t msg;
	XF86VidModeGamma gamma;
	int ret = 0;

	XF86VidModeGetGamma(video->dpy, video->screen, &gamma);

	if ((gamma.red == video->gamma_red) &&
	    (gamma.green == video->gamma_green) &&
	    (gamma.blue == video->gamma_blue))
		return 0; /* nothing to update */

	msg_hdr.type = GLC_MESSAGE_COLOR;
	msg.id = video->id;
	msg.red = gamma.red;
	msg.green = gamma.green;
	msg.blue = gamma.blue;

	/** \todo figure out brightness and contrast */
	msg.brightness = msg.contrast = 0;

	glc_log(gl_capture->glc, GLC_INFO, "gl_capture",
		 "color correction: brightness=%f, contrast=%f, red=%f, green=%f, blue=%f",
		 msg.brightness, msg.contrast, msg.red, msg.green, msg.blue);

	if (unlikely((ret = ps_packet_open(&video->packet, PS_PACKET_WRITE))))
		goto err;
	if (unlikely((ret = ps_packet_write(&video->packet,
				&msg_hdr, sizeof(glc_message_header_t)))))
		goto err;
	if (unlikely((ret = ps_packet_write(&video->packet,
				&msg, sizeof(glc_color_message_t)))))
		goto err;
	if (unlikely((ret = ps_packet_close(&video->packet))))
		goto err;

	return 0;

err:
	ps_packet_cancel(&video->packet);

	glc_log(gl_capture->glc, GLC_ERROR, "gl_capture",
		 "can't write gamma correction information to buffer: %s (%d)",
		 strerror(ret), ret);
	return ret;
}
Exemple #5
0
int alsa_play_play(alsa_play_t alsa_play, glc_audio_data_header_t *audio_hdr, char *data)
{
	snd_pcm_uframes_t frames, rem;
	snd_pcm_sframes_t ret = 0;
	unsigned int c;

	if (audio_hdr->id != alsa_play->id)
		return 0;

	if (!alsa_play->pcm) {
		glc_log(alsa_play->glc, GLC_ERROR, "alsa_play", "broken stream %d",
			 alsa_play->id);
		return EINVAL;
	}

	frames = snd_pcm_bytes_to_frames(alsa_play->pcm, audio_hdr->size);
	glc_utime_t time = glc_state_time(alsa_play->glc);
	glc_utime_t duration = ((glc_utime_t) 1000000000 * (glc_utime_t) frames) /
			       (glc_utime_t) alsa_play->rate;

	if (time + alsa_play->silence_threshold + duration < audio_hdr->time) {
		struct timespec ts = {
		.tv_sec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)/1000000000,
		.tv_nsec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)%1000000000 };
		nanosleep(&ts,NULL);
	}
	/*
	 * This condition determine what will be the initial audio packet.
	 * it is preferable to be ahead by < duration/2 than behind
	 * the video by > duration/2
	 */
	else if (time > audio_hdr->time + duration/2) {
		glc_log(alsa_play->glc, GLC_DEBUG, "alsa_play",
			"dropped packet. now %" PRId64 " ts %" PRId64,
			time, audio_hdr->time);
		return 0;
	}

	rem = frames;

	while (rem > 0) {
		/* alsa is horrible... */
		/*snd_pcm_wait(alsa_play->pcm, duration);*/

		if (alsa_play->flags & GLC_AUDIO_INTERLEAVED)
			ret = snd_pcm_writei(alsa_play->pcm,
					    &data[snd_pcm_frames_to_bytes(alsa_play->pcm, frames - rem)],
					    rem);
		else {
			for (c = 0; c < alsa_play->channels; c++)
				alsa_play->bufs[c] =
					&data[snd_pcm_samples_to_bytes(alsa_play->pcm, frames)
					      * c + snd_pcm_samples_to_bytes(alsa_play->pcm, frames - rem)];
			ret = snd_pcm_writen(alsa_play->pcm, alsa_play->bufs, rem);
		}

		if (ret == 0)
			break;

		if ((ret == -EBUSY) || (ret == -EAGAIN))
			break;
		else if (ret < 0) {
			if ((ret = alsa_play_xrun(alsa_play, ret))) {
				glc_log(alsa_play->glc, GLC_ERROR, "alsa_play",
					 "xrun recovery failed: %s", snd_strerror(-ret));
				return ret;
			}
		} else
			rem -= ret;
	}

	return 0;
}
Exemple #6
0
/*
 * Might be called from signal handlers.
 */
int alsa_hook_mmap_commit(alsa_hook_t alsa_hook, snd_pcm_t *pcm,
				snd_pcm_uframes_t offset, snd_pcm_uframes_t frames)
{
	struct alsa_hook_stream_s *stream;
	unsigned int c;
	int ret = 0;
	int savedErrno = errno;

	if (!(alsa_hook->flags & ALSA_HOOK_CAPTURING))
		goto leave;

	alsa_hook_get_stream(alsa_hook, pcm, &stream);

	if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream))))
		goto leave;

	if (unlikely(stream->channels == 0))
		goto unlock; /* 0 channels :P */

	if (unlikely(!stream->mmap_areas)) {
		/* this might actually happen */
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_WARN, "alsa_hook",
				 "snd_pcm_mmap_commit() before snd_pcm_mmap_begin()");
		goto unlock;
	}

	if (unlikely(offset != stream->offset))
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_WARN, "alsa_hook",
				 "offset=%lu != stream->offset=%lu", offset, stream->offset);

	if (unlikely((ret = alsa_hook_wait_for_thread(alsa_hook, stream))))
		goto unlock;

	if (unlikely((ret = alsa_hook_set_data_size(stream,
			snd_pcm_frames_to_bytes(pcm, frames)))))
		goto unlock;

	stream->capture_time = glc_state_time(alsa_hook->glc);

	if (stream->flags & GLC_AUDIO_INTERLEAVED) {
		memcpy(stream->capture_data,
		       alsa_hook_mmap_pos(stream->mmap_areas, offset),
		       stream->capture_size);
	} else if (stream->complex) {
		alsa_hook_complex_to_interleaved(stream, stream->mmap_areas, offset,
		                                  frames, stream->capture_data);
	} else {
		for (c = 0; c < stream->channels; c++)
			memcpy(&stream->capture_data[c * snd_pcm_samples_to_bytes(stream->pcm, frames)],
			       alsa_hook_mmap_pos(&stream->mmap_areas[c], offset),
			       snd_pcm_samples_to_bytes(stream->pcm, frames));
	}

	sem_post(&stream->capture_full);

unlock:
	alsa_hook_unlock_write(alsa_hook, stream);
leave:
	errno = savedErrno;
	return ret;
}