Commit bb4878ad authored by Mikhail Karpenko's avatar Mikhail Karpenko

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
...@@ -4,19 +4,19 @@ TEST_PROG = camogm_test ...@@ -4,19 +4,19 @@ TEST_PROG = camogm_test
PHPSCRIPTS = camogmstate.php $(GUIDIR)/camogmgui.php $(GUIDIR)/camogmgui.css $(GUIDIR)/camogmgui.js $(GUIDIR)/camogm_interface.php \ 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)/SpryTabbedPanels.css $(GUIDIR)/SpryTabbedPanels.js $(GUIDIR)/xml_simple.php $(GUIDIR)/SpryCollapsiblePanel.css \
$(GUIDIR)/SpryCollapsiblePanel.js $(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 \ 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/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/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 $(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 TEST_SRC = camogm_test.c
OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o)
CFLAGS += -Wall -I$(STAGING_DIR_HOST)/usr/include-uapi CFLAGS += -Wall -I$(STAGING_DIR_HOST)/usr/include-uapi
LDLIBS += -logg -pthread -lm LDLIBS += -logg -pthread -lm -lasound
INSTALL = install INSTALL = install
INSTMODE = 0755 INSTMODE = 0755
......
This diff is collapsed.
...@@ -22,10 +22,13 @@ ...@@ -22,10 +22,13 @@
#include <pthread.h> #include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <ogg/ogg.h> #include <ogg/ogg.h>
#include "ogmstreams.h"
#include <elphel/exifa.h> #include <elphel/exifa.h>
#include <elphel/c313a.h> #include <elphel/c313a.h>
#include <elphel/x393_devices.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_NOT_READY 1 ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer
...@@ -256,6 +259,8 @@ typedef struct { ...@@ -256,6 +259,8 @@ typedef struct {
uint16_t sock_port; ///< command socket port number uint16_t sock_port; ///< command socket port number
struct writer_params writer_params; ///< contains control parameters for writing thread struct writer_params writer_params; ///< contains control parameters for writing thread
unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors
struct audio audio; ///< various parameters related to audio
} camogm_state; } camogm_state;
extern int debug_level; extern int debug_level;
......
This diff is collapsed.
/**
* @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 */
...@@ -66,12 +66,15 @@ int quicktime_template_parser(camogm_state *state, ...@@ -66,12 +66,15 @@ int quicktime_template_parser(camogm_state *state,
void putBigEndian(unsigned long d, int l); void putBigEndian(unsigned long d, int l);
int parse_special(void); int parse_special(void);
int parse(camogm_state *state, int top); int parse(camogm_state *state, int top);
static int camogm_audio_mov(void *buff, int len, int slen);
/** /**
* @brief Called when format is changed to MOV (only once) and recording is stopped. * @brief Called when format is changed to MOV (only once) and recording is stopped.
* Read frame template from the file if it is not done yet. * @param[in] state a pointer to a structure containing current state
* Read frame template from the file if it is not done yet and set callback function for
* audio stream recording.
*/ */
int camogm_init_mov(void) int camogm_init_mov(camogm_state *state)
{ {
FILE* qt_header; FILE* qt_header;
int size; int size;
...@@ -96,6 +99,7 @@ int camogm_init_mov(void) ...@@ -96,6 +99,7 @@ int camogm_init_mov(void)
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
q_template[size] = 0; q_template[size] = 0;
state->audio.write_samples = camogm_audio_mov;
return 0; return 0;
} }
...@@ -160,6 +164,22 @@ int camogm_frame_mov(camogm_state *state) ...@@ -160,6 +164,22 @@ int camogm_frame_mov(camogm_state *state)
return 0; return 0;
} }
/**
* Write audio samples to file.
* @param buff
* @param len
* @param slen
* @return
*/
static int camogm_audio_mov(void *buff, int len, int slen)
{
int ret_val = 0;
D6(fprintf(debug_file, "write audio sample, len = %d, slen = %d\n", len, slen));
return ret_val;
}
/** /**
* @brief Move to the start of the file and insert generated header * @brief Move to the start of the file and insert generated header
* @param[in] state pointer to the #camogm_state structure for current sensor port * @param[in] state pointer to the #camogm_state structure for current sensor port
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#include "camogm.h" #include "camogm.h"
int camogm_init_mov(void); #define SAMPLE_DESCR_ID_AUDIO 1 //< audio sample description ID, used in sample-to-chunk atom
int camogm_init_mov(camogm_state *state);
int camogm_start_mov(camogm_state *state); int camogm_start_mov(camogm_state *state);
int camogm_frame_mov(camogm_state *state); int camogm_frame_mov(camogm_state *state);
int camogm_end_mov(camogm_state *state); int camogm_end_mov(camogm_state *state);
......
{'moov
{'mvhd
00 # version
000000 # Flags
!time # Creation time
!time # Modification time
!timescale # Time Scale - time unints per second
!duration # Duration - in time units
00010000 # Preferred rate
0100 # Preferred volume
00000000 00000000 0000 # (reserved)
00010000 00000000 00000000 # Matrix [a b u]
00000000 00010000 00000000 # Matrix [c d v]
00000000 00000000 40000000 # Matrix [x y w]
00000000 # Preview Time
00000000 # Preview Duration
00000000 # Poster Time
00000000 # Selection Time
00000000 # Selection Duration
00000000 # Current Time
00000002 # Next Track ID
} # 'mvhd
{'trak
{'tkhd
00 # version
00000f # Flags
!time # Creation time
!time # Modification time
00000001 # Track ID
00000000 # (reserved)
!duration # Duration
00000000 00000000 # (reserved)
0000 # Layer
0000 # Alternate group
0000 # Volume
0000 # (reserved)
00010000 00000000 00000000 # Matrix [a b u]
00000000 00010000 00000000 # Matrix [c d v]
00000000 00000000 40000000 # Matrix [x y w]
!width 0000 # Track width
!height 0000 # Track height
} # 'tkhd
{'mdia
{'mdhd
00 # version
000000 # Flags
!time # Creation time
!time # Modification time
!timescale # Time Scale
!duration # Duration
0000 # Language
0000 # Quality
} # 'mdhd
{'hdlr
00 # version
000000 # Flags
'mhlr # Component type
'vide # Component subtype
'appl # Component manufacturer
00000000 # Component Flags
0001001f # Component Flags Mask
19 'Apple Video Media Handler # Component Name
} # 'hdlr
{'minf
{'vmhd
00 # version
000001 # Flags
0040 # Graphics Mode
8000 8000 8000 # Opcolor
} # 'vmhd
{'hdlr
00 # version
000000 # Flags
'dhlr # Component type
'alis # Component subtype
'appl # Cmponent manufacturer
00000001 # Component Flags
00010026 # Component Flags Mask
18 'Apple Alias Data Handler # Component Name
} # 'hdlr
{'dinf
{'dref
00 # version
000000 # Flags (1 - the same file???)
00000001 # Number of entries
0000000c 616c6973 00000001 # Data references
}
} # 'dinf
{'stbl
{'stsd
00 # version
000000 # Flags
00000001 # Number of entries
00000056 # Sample description size
'jpeg # Data format
00000000 0000 # (reserved)
0001 # Data reference index
0000 # Version
0000 # Revision Level
'appl # Vendor
00000000 # Temporal quality
00000200 # Spatial quality
!width # Width
!height # Height
00480000 # Horizontal resolution
00480000 # Vertical resolution
00000000 # Data size
0001 # Frame count
0c 'Photo - JPEG # Compressor Name
00000000 00000000 00000000 00000000 000000 # padding
0018 # Color depth (24)
ffff # Color table ID
} #'stsd
{'stts
00 # version
000000 # Flags
00000001 # Number of entries
!nframes !frame_duration # TIME-TO-SAMPLE table (was 0x0a 0x28) - time units/sample
}
{'stsc
00 # version
000000 # Flags
00000001 # Number of entries
# 00000001 !nframes 00000001 # SAMPLE-TO-CHUNK table - all in one chunk
00000001 !samples_chunk 00000001 # SAMPLE-TO-CHUNK table - each sample it new chunk
}
{'stsz
00 # version
000000 # Flags
00000000 # Sample Size ** Did not work with non-zero!
!nframes # Number of entries
!sample_sizes # nframes of 4-byte words
}
{'stco
00 # version
000000 # Flags
# 00000001 # Number of entries
# !mdata #
# !nframes # Number of entries
!chunk_offsets #
}
} #'stbl
} #'minf
} # 'mdia
# {'udta
# 00000000
# }
} #'trak
# sound track
{'trak
{'tkhd
00 # Version
00000f # Flags
!time # Creation time
!time # Modification time
00000002 # Track ID
00000000 # (reserved)
!duration # Duration (correct)
00000000 # (reserved)
00000000 # (reserved)
0000 # Layer
0000 # Alternate group
0100 # Volume
0000 # (reserved)
00010000 00000000 00000000 # Matrix [a b u]
00000000 00010000 00000000 # Matrix [c d v]
00000000 00000000 40000000 # Matrix [x y w]
00000000 # Track width
00000000 # Track height
} #'tkhd
{'mdia
{'mdhd # - required
00 # version
000000 # Flags
!time # Creation time
!time # Modification time
!audio_timescale # Time Scale - 44100 // ???
!audio_duration # Duration // ???
0000 # Language
0000 # Quality
} # 'mdhd
{'hdlr # - not required
00 # version
000000 # Flags
'mhlr # Component type
'soun # Component subtype
00000000 # Component manufacturer
# 'niko # Component manufacturer
00000000 # Component Flags
00000000 # Component Flags Mask
00 # Component name
# 'appl # Component manufacturer
# 00000001 # Component Flags
# 00010026 # Component Flags Mask
# 18 'Apple Sound Data Handler # Component Name
} # 'hdlr
{'minf
{'smhd
00 # version
000000 # Flags
0000 # Balance
0000 # Reserved
} # 'smhd
{'hdlr
00 # version
000000 # Flags
'dhlr # Component type
'alis # Component subtype
00000000 # Component manufacturer
# 'niko # Component manufacturer
00000000 # Component Flags
00000000 # Component Flags Mask
00 #
# 00000001 # Component Flags
# 00010026 # Component Flags Mask
#18 'Apple Alias Data Handler # Component Name
} # 'hdlr
{'dinf
{'dref
00 # version
000000 # Flags (1 - the same file???)
00000001 # Number of entries
{'alis
00000001
}
}
} # 'dinf
{'stbl # Sample Table atom
{'stsd # Sample Description atom
00 # Version
000000 # Flags
00000001 # Number of entries
{'sowt # 16 bit LE, Data format
# 0001 # Version
# 0000 # Revision
00000000 0000 # (reserved)
0001 # Data reference index
0001 # Version
0000 # Revision level
00000000 # Vendor
!audio_channels # 2b, Number of channels
0010 # Sample size, == 0x10 == 16 bit
0000 # Compression ID
0000 # Packet size
!audio_rate # 4b, Sample rate - unsigned 16.16 FP
# new fields...
00000001 # samples per packets - always 1
00000002 # number of bytes in a sample for a single channel
!audio_bytes_per_frame # bytes per frame - 2 * channels
00000002 # bytes per sample - 2
# 00000000 # Terminator
# 00000000
}
} # 'stsd
{'stts # Time-to-sample atom - from the "Some Useful Examples: Creating Audio Tracks at 44.1 kHz"
00 # version
000000 # Flags
# !audio_stts #
00000001 # Number of entries
!audio_samples # Samples count
00000001 # Sample duration
}
{'stsc # Sample-to-chunk atom - OK
00 # version
000000 # Flags
!audio_stsc #
# 00000000 # Number of entries
#[ 00000000 # first chunk
#... 00000000 # samples per chunk
#] 00000000 # samples description ID - 01 or 02 ?
}
{'stsz # Sample size atom
00 # version
000000 # Flags
!audio_stsz # Sample Size - 2 for Mono, 4 for Stereo - ?
# 00000000 # Number of entries - empty
}
{'stco # Chunk offset atom
00 # version
000000 # Flags
!audio_stco #
}
} # 'stbl
} # 'minf
} #'mdia
} #'trak
# {'udta
# {'WLOC
# 0017
# 0020
# }
# 00000000 # ???
# }
}
!data_size
'mdat
/**
* @file thelper.c
* @brief Various helper functions to work with timeval structures
* @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/>.
*/
#include "thelper.h"
/**
* Make sure that time represented by timeval structure has correct format, i.e.
* the value of microseconds does not exceed 1000000.
* @param tv time values to normalize
* @return None
*/
void time_normalize(struct timeval *tv)
{
tv->tv_sec += tv->tv_usec / 1000000;
tv->tv_usec = tv->tv_usec % 1000000;
}
/**
* Compare two times represented by timeval structure
* @param t1 first time value
* @param t2 second time value
* @return 1 if t1 > t2, 0 in case values are equal and -1 if t1 < t2
*/
int time_comp(struct timeval *t1, struct timeval *t2)
{
if (t1->tv_sec > t2->tv_sec)
return 1;
if (t1->tv_sec == t2->tv_sec) {
if (t1->tv_usec > t2->tv_usec)
return 1;
if (t1->tv_usec == t2->tv_usec)
return 0;
}
return -1;
}
/**
* @file thelper.h
* @brief Various helper functions to work with timeval structures
* @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 _THELPER_H
#define _THELPER_H
#include <sys/time.h>
void time_normalize(struct timeval *tv);
int time_comp(struct timeval *t1, struct timeval *t2);
#endif /* _THELPER_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment