Commit bb4878ad authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Add basic audio functions

This commit starts to add audio recording to camogm. Basic code for ALSA
initialization and audio samples reading is added but recording to file
has not been implemented yet.
parent 23bac812
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -4,19 +4,19 @@ TEST_PROG = camogm_test
PHPSCRIPTS = camogmstate.php $(GUIDIR)/camogmgui.php $(GUIDIR)/camogmgui.css $(GUIDIR)/camogmgui.js $(GUIDIR)/camogm_interface.php \
             $(GUIDIR)/SpryTabbedPanels.css $(GUIDIR)/SpryTabbedPanels.js $(GUIDIR)/xml_simple.php $(GUIDIR)/SpryCollapsiblePanel.css \
             $(GUIDIR)/SpryCollapsiblePanel.js
CONFIGS    = qt_source
CONFIGS    = qt_source qt_audio
IMAGES     = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bottom-01.gif $(GUIDIR)/images/png_white_30.png \
             $(GUIDIR)/images/record.gif $(GUIDIR)/images/reload.png $(GUIDIR)/images/stop.gif $(GUIDIR)/images/create_folder.png \
             $(GUIDIR)/images/divider.png $(GUIDIR)/images/folder.gif $(GUIDIR)/images/help.png $(GUIDIR)/images/quicktime.png \
             $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png


SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c camogm_align.c
SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c camogm_align.c camogm_audio.c thelper.c
TEST_SRC = camogm_test.c
OBJS = $(SRCS:.c=.o)

CFLAGS    += -Wall -I$(STAGING_DIR_HOST)/usr/include-uapi
LDLIBS    += -logg -pthread -lm
LDLIBS    += -logg -pthread -lm -lasound

INSTALL    = install
INSTMODE   = 0755
+222 −50
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <getopt.h>
#include <ctype.h>
@@ -35,6 +36,7 @@
#include "camogm_mov.h"
#include "camogm_kml.h"
#include "camogm_read.h"
#include "thelper.h"

/** @brief Default debug level */
#define DEFAULT_DEBUG_LVL         6
@@ -61,6 +63,10 @@
#define ALL_CHN_INACTIVE          0x00
/** @brief This is a basic helper macro for processing all sensor ports at a time */
#define FOR_EACH_PORT(indtype, indvar) for (indtype indvar = 0; indvar < SENSOR_PORTS; indvar++)
/** @brief container_of macro as in the kernel */
#define container_of(ptr, type, member) ({                      \
             const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
             (type *)( (char *)__mptr - offsetof(type,member) );})

char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };

@@ -112,8 +118,8 @@ int debug_level;
FILE* debug_file;

void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num);
int camogm_start(camogm_state *state);
int camogm_stop(camogm_state *state);
int camogm_start(camogm_state *state, bool restart);
int camogm_stop(camogm_state *state, bool reset);
void camogm_reset(camogm_state *state);
int camogm_debug(camogm_state *state, const char *fname);
int camogm_debug_level(int d);
@@ -152,6 +158,7 @@ static int get_disk_range(const char *name, struct range *rng);
static int set_disk_range(const struct range *rng);
static void get_disk_info(camogm_state *state);
static struct timeval get_fpga_time(const int fd_fparsall, unsigned int port);
static void get_fpga_time_w(const struct audio *audio, struct timeval *tv);
int open_files(camogm_state *state);
unsigned long getGPValue(unsigned int port, unsigned long GPNumber);
void setGValue(unsigned int port, unsigned long GNumber, unsigned long value);
@@ -162,6 +169,10 @@ void clean_up(camogm_state *state);
static void camogm_err_stat(const camogm_state *state, int port, FILE *f, bool xml);
static void camogm_set_dummy_read(camogm_state *state, int d);

static void camogm_set_audio_state(camogm_state *state, char *args);
static void camogm_set_audio_volume(camogm_state *state, char *args);
static void camogm_set_audio_format(camogm_state *state, char *args);

void put_uint16(void *buf, u_int16_t val)
{
	unsigned char  *tmp;
@@ -271,6 +282,13 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num)
	state->writer_params.state = STATE_STOPPED;

	camogm_set_dummy_read(state, 0);

	// audio stuff
	state->audio.dev_name = DEFAULT_SND_DEVICE;
	state->audio.set_audio_channels = SAMPLE_CHANNELS;
	state->audio.set_audio_rate = SAMPLE_RATE;
	state->audio.set_audio_volume = DEFAULT_AUDIO_VOLUME;
	state->audio.get_fpga_time = get_fpga_time_w;
}

/**
@@ -311,9 +329,10 @@ int camogm_debug_level(int d)
/**
 * @brief Start recording for each active sensor port
 * @param[in]   state   a pointer to a structure containing current state
 * @param[in]   restart flag indicating that full restart is requested
 * @return      0 if the recording finished successfully and negative error code otherwise
 */
int camogm_start(camogm_state *state)
int camogm_start(camogm_state *state, bool restart)
{
	int timestamp_start;
	int rslt;
@@ -338,13 +357,14 @@ int camogm_start(camogm_state *state)
	int * ifp_this = (int*)&(state->this_frame_params[port]);
	if (state->kml_enable) camogm_init_kml();  // do nothing

	audio_init(&state->audio, restart);
	if (state->format != state->set_format) {
		state->format =  state->set_format;
		switch (state->format) {
		case CAMOGM_FORMAT_NONE: rslt = 0; break;
		case CAMOGM_FORMAT_OGM:  rslt = camogm_init_ogm(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(state); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(state); break;
		}
		state->formats |= 1 << (state->format);
		// exit on unknown formats?
@@ -483,6 +503,7 @@ int camogm_start(camogm_state *state)
	}

	// here we are ready to initialize Ogm (or other) file
	audio_start(&state->audio);
	switch (state->format) {
	case CAMOGM_FORMAT_NONE: rslt = 0;  break;
	case CAMOGM_FORMAT_OGM:  rslt = camogm_start_ogm(state);  break;
@@ -519,9 +540,6 @@ int sendImageFrame(camogm_state *state)
	int * ifp_this = (int*)&(state->this_frame_params[state->port_num]);
	int fp;
	int port = state->port_num;
	struct timeval start_time, end_time;

//	start_time = get_fpga_time(state->fd_fparmsall[port], port);

// This is probably needed only for Quicktime (not to exceed already allocated frame index)
	if (!state->rawdev_op && (state->frameno >= (state->max_frames))) {
@@ -666,6 +684,58 @@ int sendImageFrame(camogm_state *state)
	state->packetchunks[state->chunk_index  ].bytes = 2;
	state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer;

	state->audio.ts_video.tv_sec = state->this_frame_params[port].timestamp_sec;
	state->audio.ts_video.tv_usec = state->this_frame_params[port].timestamp_usec;
	int sync_ok = 1;
	// synchronize audio and video before recording has started, this need to be done only once
	if (state->audio.ctx_a.begin_of_stream_with_audio) {
		D6(fprintf(debug_file, "\n"));
		if (state->audio.ctx_a.audio_trigger) {
			state->audio.ts_video_start = state->audio.ts_audio;
			state->audio.ts_video_start.tv_usec += state->frame_period[port] / 2;
			time_normalize(&state->audio.ts_video_start);
			state->audio.ctx_a.audio_trigger = 0;
			// calculate how many audio samples we need to skip here
			long audio_to_skip = 0;
			struct timeval tv = state->audio.ts_video;
			while (time_comp(&tv, &state->audio.ts_video_start) < 0) {
				tv.tv_usec += state->frame_period[port];
				time_normalize(&tv);
			}
			tv.tv_sec -= 1;
			tv.tv_usec += 1000000;
			tv.tv_usec -= state->frame_period[port] / 2;
			time_normalize(&tv);
			if (tv.tv_sec != state->audio.ts_audio.tv_sec) {
				audio_to_skip = tv.tv_sec - state->audio.ts_audio.tv_sec;
				audio_to_skip *= 1000000;
			}
			audio_to_skip += tv.tv_usec;
			audio_to_skip -= state->audio.ts_audio.tv_usec;
			double s = state->audio.audio_rate;
			s /= 1000.0;
			s *= audio_to_skip;
			s /= 1000.0;
			state->audio.ctx_a.audio_skip_samples = (long) s;
			state->audio.ctx_a.time_start = tv;
			D6(fprintf(debug_file , "audio started at: %ld:%06ld; we need to record it from: %ld:%06ld; audio_to_skip_us == %ld; "
					"audio samples to skip == %lld\n",
					state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, tv.tv_sec, tv.tv_usec, audio_to_skip,
					state->audio.ctx_a.audio_skip_samples));
		}
		D6(fprintf(debug_file, "audio (start): %ld:%06ld; video (current): %ld:%06ld; frame period is: %d us\n",
				state->audio.ts_audio.tv_sec, state->audio.ts_audio.tv_usec, state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec,
				state->frame_period[port]));
		if (time_comp(&state->audio.ts_video_start, &state->audio.ts_video) > 0) {
			D6(fprintf(debug_file, "skip this video frame\n"));
			sync_ok = 0;
		} else {
			D6(fprintf(debug_file, "save video frame with time: %ld:%06ld\n", state->audio.ts_video.tv_sec, state->audio.ts_video.tv_usec));
			state->audio.ctx_a.begin_of_stream_with_audio = 0;
		}
	}

	if (sync_ok) {
		switch (state->format) {
		case CAMOGM_FORMAT_NONE: rslt = 0; break;
		case CAMOGM_FORMAT_OGM:  rslt = camogm_frame_ogm(state); break;
@@ -673,6 +743,10 @@ int sendImageFrame(camogm_state *state)
		case CAMOGM_FORMAT_MOV:  rslt = camogm_frame_mov(state); break;
		default: rslt = 0; // do nothing
		}
	} else {
		// skip only first video frames that are ahead of audio stream
		rslt = 0;
	}
	if (rslt) {
		D3(fprintf(debug_file, "sendImageFrame:12: camogm_frame_***() returned %d\n", rslt));
		return rslt;
@@ -682,6 +756,7 @@ int sendImageFrame(camogm_state *state)

	D3(fprintf(debug_file, "_14_"));
	// advance frame pointer
	if (sync_ok)
		state->frameno++;
	state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END);
	D3(fprintf(debug_file, "\tcompressed frame number: %li\t", lseek(state->fd_circ[port], LSEEK_CIRC_GETFRAME, SEEK_END)));
@@ -695,17 +770,6 @@ int sendImageFrame(camogm_state *state)
	}
	D3(fprintf(debug_file,"cirbuf_rp to next frame = 0x%x\n", state->cirbuf_rp[port]));

//	end_time = get_fpga_time(state->fd_fparmsall[port], port);
//	unsigned int mbps; // write speed, MB/s
//	unsigned long long time_diff; // time elapsed, in microseconds
//	time_diff = ((end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec));
//	mbps = ((double)state->rawdev.last_jpeg_size / (double)1048576) / ((double)time_diff / (double)1000000);
//	D6(fprintf(debug_file, "Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu\n",
//			start_time.tv_sec, start_time.tv_usec,
//			end_time.tv_sec, end_time.tv_usec,
//			state->rawdev.last_jpeg_size));
//	D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps));

	return 0;
}

@@ -713,9 +777,10 @@ int sendImageFrame(camogm_state *state)
 * @brief Stop current recording. If recording was not started, this function has no effect. This function
 * calls @e camogm_end_* for the current file format.
 * @param[in]   state   a pointer to a structure containing current state
 * @param[in]   reset   flag indicating that sound HW should be reset as well
 * @return      0 if the operation was stopped successfully and negative error code otherwise
 */
int camogm_stop(camogm_state *state)
int camogm_stop(camogm_state *state, bool reset)
{
	int rslt = 0;

@@ -730,8 +795,10 @@ int camogm_stop(camogm_state *state)
		}
		return 0;
	}
	D1(fprintf(debug_file, "Ending recording\n"));
	D1(fprintf(debug_file, "Stop recording\n"));
	if (state->kml_used) camogm_end_kml(state);
	if (state->audio.audio_enable)
		audio_finish(&state->audio, reset);
	switch (state->format) {
	case CAMOGM_FORMAT_NONE: rslt = 0; break;
	case CAMOGM_FORMAT_OGM:  rslt = camogm_end_ogm(state); break;
@@ -935,7 +1002,7 @@ void camogm_set_format(camogm_state *state, int d)
		case CAMOGM_FORMAT_NONE: rslt = 0; break;
		case CAMOGM_FORMAT_OGM:  rslt = camogm_init_ogm(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(state); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(state); break;
		}
		if (rslt) {
			D0(fprintf(debug_file, "%s:%d: Error setting format to=%d\n", __FILE__, __LINE__, state->format));
@@ -966,6 +1033,65 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d)
	state->start_after_timestamp =  d;
}

/** @brief Change audio processing state */
static void camogm_set_audio_state(camogm_state *state, char *args)
{
	if (strncmp(args, "on", 2) == 0 || strncmp(args, "enable", 6) == 0) {
		state->audio.set_audio_enable = 1;
	} else if (strncmp(args, "off", 3) == 0 || strncmp(args, "disable", 7) == 0){
		state->audio.set_audio_enable = 0;
	}
}

/** @brief Set audio volume */
static void camogm_set_audio_volume(camogm_state *state, char *args)
{
	int vol = atoi(args);

	if (vol > 65535)
		vol = 65535;
	if (vol < 0)
		vol = 0;
	state->audio.set_audio_volume = vol;
}

/** @brief Set audio sample rate and number of channels */
static void camogm_set_audio_format(camogm_state *state, char *args)
{
	char buf[8];
	int i;
	int channels = -1;
	int rate = -1;
	char *right = strstr(args, "/");

	if (right != NULL) {
		channels = atol(&right[1]);
		if (channels < AUDIO_CHANNELS_MIN)
			channels = AUDIO_CHANNELS_MIN;
		if (channels > AUDIO_CHANNELS_MAX)
			channels = AUDIO_CHANNELS_MAX;
		state->audio.set_audio_channels = channels;
	}
	for (i = 0; i < 7; i++) {
		if (args[i] != '\0' && args[i] != '/')
			buf[i] = args[i];
		else
			break;
	}
	buf[i] = '\0';
	if (buf[0] != '\0') {
		rate = atol(buf);
		if (rate < AUDIO_RATE_MIN)
			rate = AUDIO_RATE_MIN;
		if (rate > AUDIO_RATE_MAX)
			rate = AUDIO_RATE_MAX;
		state->audio.set_audio_rate = rate;
	}

	D6(fprintf(debug_file, "request for audio format: %s; set rate = %d, channels = %d\n",
			args, state->audio.set_audio_rate, state->audio.set_audio_channels));
}

/**
 * @brief Print current status either as plain text or in xml format
 * @param[in]   state   to a structure containing current state
@@ -987,6 +1113,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
	int _frames_skip = 0;
	int _sec_skip = 0;
	char *_kml_enable, *_kml_used, *_kml_height_mode;
	char *_audio_en;
	unsigned int _percent_done;
	off_t save_p;

@@ -1069,6 +1196,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
	else
		_percent_done = 0;

	_audio_en = state->audio.set_audio_enable ? "yes" : "no";
	if (xml) {
		fprintf(f, "<?xml version=\"1.0\"?>\n" \
			"<camogm_state>\n" \
@@ -1112,18 +1240,25 @@ void camogm_status(camogm_state *state, char * fn, int xml)
			"  <raw_device_pos_read>0x%llx (%d%% done)</raw_device_pos_read>\n" \
			"  <lba_start>%llu</lba_start>\n" \
			"  <lba_current>%llu</lba_current>\n" \
			"  <lba_end>%llu</lba_end>\n",
			_state,  state->path, state->frameno, state->start_after_timestamp, _dur, _udur, _len, \
			_frames_skip, _sec_skip, \
			state->width, state->height, _output_format, _using_exif, \
			state->path_prefix, state->segment_duration, state->segment_length, state->max_frames, state->timescale, \
			state->frames_per_chunk,  state->last_error_code, \
			state->debug_name, debug_level, _using_global_pointer, \
			_kml_enable, _kml_used, state->kml_path, state->kml_horHalfFov, state->kml_vertHalfFov, state->kml_near, \
			_kml_height_mode, state->kml_height, state->kml_period, state->kml_last_ts, state->kml_last_uts, \
			"  <lba_end>%llu</lba_end>\n" \

			"  <audio_enable>%s</audio_enable>\n" \
			"  <audio_channels>%d</audio_channels>\n" \
			"  <audio_rate>%d</audio_rate>\n" \
			"  <audio_volume>%d</audio_volume>\n",
			_state,  state->path, state->frameno, state->start_after_timestamp, _dur, _udur, _len,
			_frames_skip, _sec_skip,
			state->width, state->height, _output_format, _using_exif,
			state->path_prefix, state->segment_duration, state->segment_length, state->max_frames, state->timescale,
			state->frames_per_chunk,  state->last_error_code,
			state->debug_name, debug_level, _using_global_pointer,
			_kml_enable, _kml_used, state->kml_path, state->kml_horHalfFov, state->kml_vertHalfFov, state->kml_near,
			_kml_height_mode, state->kml_height, state->kml_period, state->kml_last_ts, state->kml_last_uts,
			state->greedy ? "yes" : "no", state->ignore_fps ? "yes" : "no", state->rawdev.rawdev_path,
			state->rawdev.overrun, state->rawdev.curr_pos_w, state->rawdev.curr_pos_r, _percent_done,
			state->writer_params.lba_start, state->writer_params.lba_current, state->writer_params.lba_end);
			state->writer_params.lba_start, state->writer_params.lba_current, state->writer_params.lba_end,

			_audio_en, state->audio.set_audio_channels, state->audio.set_audio_rate, state->audio.set_audio_volume);

		FOR_EACH_PORT(int, chn) {
			char *_active = is_chn_active(state, chn) ? "yes" : "no";
@@ -1204,6 +1339,11 @@ void camogm_status(camogm_state *state, char * fn, int xml)
		fprintf(f, "lba_current        \t%llu\n",      state->writer_params.lba_current);
		fprintf(f, "lba_end            \t%llu\n",      state->writer_params.lba_end);
		fprintf(f, "\n");
		fprintf(f, "audio_enable       \t%s\n",        _audio_en);
		fprintf(f, "audio_channels     \t%d\n",        state->audio.set_audio_channels);
		fprintf(f, "audio_rate         \t%d\n",        state->audio.set_audio_rate);
		fprintf(f, "audio_volume       \t%d\n",        state->audio.set_audio_volume);
		fprintf(f, "\n");
		FOR_EACH_PORT(int, chn) {
			char *_active = is_chn_active(state, chn) ? "yes" : "no";
			fprintf(f, "===== Sensor port %d status =====\n", chn);
@@ -1349,17 +1489,18 @@ int parse_cmd(camogm_state *state, FILE* npipe)
// now cmd is trimmed, arg is NULL or a pointer to trimmed command arguments
	if (strcmp(cmd, "start") == 0) {
		check_compressors(state);
		if (state->rawdev_op)
			get_disk_info(state);
		camogm_start(state);
		camogm_start(state, true);
		return 1;
	} else if (strcmp(cmd, "reset") == 0) { // will reset pointer to the last acquired frame (if any)
		camogm_reset(state);
		return 2;
	} else if (strcmp(cmd, "stop") == 0) {
		camogm_stop(state);
		camogm_stop(state, true);
		return 3;
	} else if (strcmp(cmd, "exit") == 0) {
		camogm_stop(state);
		camogm_stop(state, true);
		camogm_free(state);
		clean_up(state);
		exit(0);
@@ -1496,6 +1637,18 @@ int parse_cmd(camogm_state *state, FILE* npipe)
	} else if (strcmp(cmd, "dummy_read") == 0) {
		if ((args) && ((d = strtol(args, NULL, 10)) > 0)) camogm_set_dummy_read(state, d);
		return 30;
	} else if (strcmp(cmd, "audio") == 0) {
		if (args)
			camogm_set_audio_state(state, args);
		return 31;
	} else if (strcmp(cmd, "audio_volume") == 0) {
		if (args)
			camogm_set_audio_volume(state, args);
		return 32;
	} else if (strcmp(cmd, "audio_format") == 0) {
		if (args)
			camogm_set_audio_format(state, args);
		return 33;
	}

	return -1;
@@ -1581,6 +1734,9 @@ int listener_loop(camogm_state *state)
		} else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started
			switch ((rslt = -sendImageFrame(state))) {
			case 0:
				if (state->format == CAMOGM_FORMAT_MOV) {
					audio_process(&state->audio);
				}
				break;                      // frame sent OK, nothing to do (TODO: check file length/duration)
			case CAMOGM_FRAME_NOT_READY:    // just wait for the frame to appear at the current pointer
				// we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands
@@ -1605,8 +1761,8 @@ int listener_loop(camogm_state *state)
			case  CAMOGM_FRAME_BROKEN:      // frame broken (buffer overrun)
				// restart the file
				D3(fprintf(debug_file,"%s:line %d - sendImageFrame() returned -%d\n", __FILE__, __LINE__, rslt));
				camogm_stop(state);
				camogm_start(state);
				camogm_stop(state, false);
				camogm_start(state, false);
				break;
			case  CAMOGM_FRAME_FILE_ERR:    // error with file I/O
			case  CAMOGM_FRAME_OTHER:       // other errors
@@ -1628,7 +1784,7 @@ int listener_loop(camogm_state *state)
		} else if (state->prog_state == STATE_STARTING) { // no commands in queue,starting (but not started yet)

			// retry starting
			switch ((rslt = -camogm_start(state))) {
			switch ((rslt = -camogm_start(state, true))) {
			case 0:
				break;                      // file started OK, nothing to do
			case CAMOGM_TOO_EARLY:
@@ -2156,3 +2312,19 @@ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port)

	return tv;
}

/**
 * Wrapper for a function returning FPGA time. This wrapper is set as a callback function for
 * audio interface. The time value is retrieved through currently active port.
 * @param[in]   audio   pointer to a structure containing audio parameters and buffers
 * @param[out]  tv      pointer to a structure where time value will be stored
 * @return      None
 */
static void get_fpga_time_w(const struct audio *audio, struct timeval *tv)
{
	unsigned int port;
	camogm_state *state = container_of(audio, camogm_state, audio);

	port = state->port_num;
	*tv = get_fpga_time(state->fd_fparmsall[port], port);
}
+6 −1
Original line number Diff line number Diff line
@@ -22,10 +22,13 @@
#include <pthread.h>
#include <stdbool.h>
#include <ogg/ogg.h>
#include "ogmstreams.h"
#include <elphel/exifa.h>
#include <elphel/c313a.h>
#include <elphel/x393_devices.h>
#include <sys/uio.h>

#include "ogmstreams.h"
#include "camogm_audio.h"

#define CAMOGM_FRAME_NOT_READY    1        ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID      2        ///< invalid frame pointer
@@ -256,6 +259,8 @@ typedef struct {
	uint16_t sock_port; 									///< command socket port number
	struct writer_params writer_params;                     ///< contains control parameters for writing thread
	unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM];   ///< collect statistics about errors

	struct audio audio;                                     ///< various parameters related to audio
} camogm_state;

extern int debug_level;

src/camogm_audio.c

0 → 100644
+401 −0

File added.

Preview size limit exceeded, changes collapsed.

src/camogm_audio.h

0 → 100644
+91 −0
Original line number Diff line number Diff line
/**
 * @file camogm_audio.h
 * @brief Provides audio interface for camogm
 * @copyright Copyright (C) 2017 Elphel Inc.
 * @author AUTHOR <EMAIL>
 *
 * @par License:
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _CAMOGM_AUDIO_H
#define _CAMOGM_AUDIO_H

#include <sys/time.h>
#include <alsa/asoundlib.h>

#define SAMPLE_RATE               44100
#define SAMPLE_CHANNELS           2
#define SAMPLE_TIME               200
#define DEFAULT_SND_DEVICE        "plughw:0,0"
#define AUDIO_SBUFFER_PREFIX      16
#define AUDIO_CHANNELS_MIN        1
#define AUDIO_CHANNELS_MAX        2
#define AUDIO_RATE_MIN            11025
#define AUDIO_RATE_MAX            44100
#define DEFAULT_AUDIO_VOLUME      0xffff

struct context_audio {
	char *sbuffer;                                              ///< buffer for audio samples
	long sbuffer_len;                                           ///< the length of samples buffer in samples
	long sample_time;                                           ///< duration of one audio sample in ms
	long long audio_count;                                      ///< total number of audio samples

	struct timeval time_start;                                  ///< start time, set only when stream starts and updated with each new file
	struct timeval time_last;                                   ///< time of last audio sample
	long rem_samples;                                           ///< remaining samples

	int begin_of_stream_with_audio;                             ///<
	int audio_trigger;                                          ///< indicates the beginning of audio recording to make some initial set ups
	long long audio_skip_samples;                               ///<

	snd_pcm_t *capture_hnd;                                     ///< ALSA PCM handle
};

struct audio {
	int audio_enable;                                           ///< flag indicating if audio is enabled
	int audio_rate;                                             ///< sample rate
	int audio_channels;                                         ///< number of channels
	int audio_volume;                                           ///< volume set in range [0..0xFFFF]

	int set_audio_enable;                                       ///< temporary storage for new value
	int set_audio_rate;                                         ///< temporary storage for new value
	int set_audio_channels;                                     ///< temporary storage for new value
	int set_audio_volume;                                       ///< temporary storage for new value

	long audio_frameno;                                         ///< frame number counter, used as index in frames_len array
	long audio_samples;                                         ///< samples counter
	unsigned long *frames_len;                                  ///< indexes of audio frames
	int *audio_samples_to_chunk;                                ///< an array of chunks, contains sample count in each chunk

	char *dev_name;                                             ///< the name of audio device to use
	struct context_audio ctx_a;                                 ///< current audio context

	struct timeval ts_audio;                                    ///< time stamp when audio stream started
	struct timeval ts_video;                                    ///< time stamp of each new frame
	struct timeval ts_video_start;                              ///< time stamp of starting video frame
	int frame_period;                                           ///< video frame period, used to calculate time stamps for audio samples

	void (*get_fpga_time)(const struct audio *audio, struct timeval *tv);//< callback function which can get FPGA time
	int (*write_samples)(void *buff, int len, int slen);        ///< callback function which actually write data to file, this must set
	                                                            ///< in the camogm_init_* function when appropriate format is selected
};

void audio_init(struct audio *audio, bool restart);
void audio_start(struct audio *audio);
void audio_process(struct audio *audio);
void audio_finish(struct audio *audio, bool reset);
void audio_set_volume(int nvolume);

#endif /* _CAMOGM_AUDIO_H */
Loading