blob: 22327a8676a9acbc414dd5d514aa7473c513b776 [file] [log] [blame]
#include "audio_if_types.h"
#include "audio_if_ubus.h"
#include "audio_if_parameter.h"
#include "audio_if.h"
#include "audio_if_api.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "telatparamdef_ubus.h"
#include <libubox/blobmsg_json.h>
#include "libubus.h"
#include <string.h>
#include "audio_if_audio_hw_mrvl.h"
#include "utlEventHandler.h"
#include "udev_monitor.h"
#include "audio_hw_mrvl.h"
#include <stdlib.h>
#include <stdio.h>
#include <cutils/str_parms.h>
#include "vcm.h"
#include <libavutil/avutil.h>
#include <libavutil/attributes.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/mathematics.h>
#include <libswresample/swresample.h>
//#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include <libswresample/swresample.h>
#include <libavfilter/avfilter.h>
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
/* the size may be modified because of different decoded sample number. */
#define MGR_BUFFER_SIZE 1024
//#define DEBUG_FFMPEG_PCM_STREAM
/* needed by PCM stream */
extern void* audio_hal_install(void);
extern void audio_hal_uninstall(void);
extern void configure_vcm(unsigned int data[]);
extern void set_pcm_config(int role, int rate);
extern int mrvl_hw_dev_config_pcm(struct audio_hw_device *dev, unsigned int pcm);
typedef struct {
char buf[MGR_BUFFER_SIZE];
int data_size;
} Mgr_buf_t;
typedef struct {
int videoindex;
int sndindex;
AVFormatContext* pFormatCtx;
AVCodecContext* sndCodecCtx;
AVCodec* sndCodec;
SwrContext *swr_ctx;
DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 2];
//DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE];
}AudioState;
/******************************************************************************
* Globals
******************************************************************************/
static audio_hw_device_t *audio_player_ahw_dev_ubus;
struct audio_stream_in *stream_in = NULL;
struct audio_stream_out *stream_out = NULL;
bool go_on_play = true;
unsigned int pcm_record_size = 0; //320:NB, 640:WB
int pcm_playback_size = 0; //320:NB, 640:WB
/* needed by FFMPEG */
extern int64_t av_get_default_channel_layout(int nb_channels);
extern AVFrame *avcodec_alloc_frame(void);
/*
typedef struct {
char buf[MGR_BUFFER_SIZE];
int data_size;
} Mgr_buf_t;
*/
Mgr_buf_t adapter_buf;
/*********************************************************/
/* buf:input parameter; size: input parameter */
static int set_adapter_buf(char *buf, int set_size)//input parameters
{
#ifdef DEBUG_FFMPEG_PCM_STREAM
printf("%s: before set: set_size=%d, adapter_buf.data_size=%d.\n", __FUNCTION__, set_size, adapter_buf.data_size);
#endif
if ((unsigned int)(adapter_buf.data_size + set_size) > sizeof(adapter_buf.buf)) {
printf("%s: out range of buf.\n", __FUNCTION__);
return -1;
}
memcpy((char *)(adapter_buf.buf) + adapter_buf.data_size, buf, set_size);
adapter_buf.data_size += set_size;
#ifdef DEBUG_FFMPEG_PCM_STREAM
printf("%s: after set: adapter_buf.data_size=%d.\n", __FUNCTION__, adapter_buf.data_size);
#endif
return 0;
}
/* buf: input parameter, size: output parameter */
static int get_adapter_buf(char *buf, int *get_size)
{
int copy_size = 0;
#ifdef DEBUG_FFMPEG_PCM_STREAM
printf("%s: before get: adapter_buf.data_size=%d.\n", __FUNCTION__, adapter_buf.data_size);
#endif
if (adapter_buf.data_size < pcm_playback_size) {
printf("%s: less than needed.\n", __FUNCTION__);
return -1;
}
/* copy the needed data to buf */
copy_size = (adapter_buf.data_size / pcm_playback_size) * pcm_playback_size;
memcpy(buf, (char *)(adapter_buf.buf), copy_size);
*get_size = copy_size;
/* move the left data to array[0] */
adapter_buf.data_size = adapter_buf.data_size % pcm_playback_size;
if (adapter_buf.data_size > 0) {
memmove((char *)(adapter_buf.buf), (char *)(adapter_buf.buf)+copy_size, adapter_buf.data_size);
}
#ifdef DEBUG_FFMPEG_PCM_STREAM
printf("%s: after get: copy_size=%d,left data_size=%d.\n", __FUNCTION__, copy_size, adapter_buf.data_size);
#endif
return 0;
}
static int my_init_ffmpeg(AudioState* is, char* filepath)
{
is->sndindex = -1;
if(NULL == filepath)
{
printf("input file is NULL");
return -1;
}
avcodec_register_all();
avfilter_register_all();
av_register_all();
is->pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&is->pFormatCtx, filepath, NULL, NULL)!=0)
return -1;
if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
return -1;
av_dump_format(is->pFormatCtx,0, 0, 0);
is->videoindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_VIDEO, is->videoindex, -1, NULL, 0);
is->sndindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_AUDIO,is->sndindex, is->videoindex, NULL, 0);
printf("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
if(is->sndindex != -1)
{
is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
if(is->sndCodec == NULL)
{
printf("Codec not found");
return -1;
}
if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
return -1;
}
return 0;
}
static int config_parameters(int in_out, int NBWB)
{
unsigned int direction = 0xFF, type, srcdst, priority, dest;
char kvpair[128];
struct str_parms *param = NULL;
int data[5];
const char *key = NULL;
bool update_vcm = false;
direction = in_out;/* 0-play, 1-record */
type = NBWB;/* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
priority = 1;/* 0-Do not combine(override), 1-Combine */
dest = 0;/* 0-Near codec, 1-Near Vocoder */
if(direction == 0){//output
if(type == 0)
pcm_playback_size = PCM_NB_BUF_SIZE;
else
pcm_playback_size = PCM_WB_BUF_SIZE;
printf("config playback parameters.\n");
}
else if(direction == 1){//input
if(type == 0)
pcm_record_size = PCM_NB_BUF_SIZE;
else
pcm_record_size = PCM_WB_BUF_SIZE;
printf("config record parameters.\n");
}
memset(kvpair, 0x00, sizeof(kvpair));
sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
printf("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
//extract the parameter and config from string
param = str_parms_create_str(kvpair);
if (!param) {
printf("%s: param create str is null!", __FUNCTION__);
return -1;
}
//set vcm configurations
key = VCM_CONFIG_DIRECTION;
if (str_parms_get_int(param, key, &data[0]) == 0) {
update_vcm = true;
str_parms_del(param, key);
}
key = VCM_CONFIG_TYPE;
if (str_parms_get_int(param, key, &data[1]) == 0) {
update_vcm = true;
str_parms_del(param, key);
}
key = VCM_CONFIG_SRC_DST;
if (str_parms_get_int(param, key, &data[2]) == 0) {
update_vcm = true;
str_parms_del(param, key);
}
key = VCM_CONFIG_PRIORITY;
if (str_parms_get_int(param, key, &data[3]) == 0) {
update_vcm = true;
str_parms_del(param, key);
}
key = VCM_CONFIG_DEST;
if (str_parms_get_int(param, key, &data[4]) == 0) {
update_vcm = true;
str_parms_del(param, key);
}
//printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
if (update_vcm) {
configure_vcm(data); /*TODO check if all inputs got all values successfully*/
}
return 0;
}
static void sig_handler(int sig)
{
go_on_play = false;
printf("output signal number: %d.\n", sig);
}
int main(int argc, char **argv)
{
int in_channel_nb = 0;
int ret, rc;
int fd;
int size;
int len;
int file_data_size = 0;
int converted_nb_samples = 0;
int got_frame;
int index =0;
int i =0;
AVPacket *packet = av_mallocz(sizeof(AVPacket));
//AVFrame *frame = av_frame_alloc();
AVFrame *frame = avcodec_alloc_frame();
AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
uint8_t *out[] = { is->audio_buf };
//char buf[MGR_BUFFER_SIZE];
enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //输出采样格式16bit PCM
int out_channel_nb = 0;
struct wav_header header;
char temp_buf[MGR_BUFFER_SIZE];
#if 1
int sample_rate = 8000;
//int sample_rate = 16000;
//int sample_rate = 44100;
int out_sample_rate = sample_rate; //输出采样率
uint64_t out_ch_layout = AV_CH_LAYOUT_MONO; //输出的声道布局
//uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; //输出的声道布局
//config playback parameters.
config_parameters(0, 0);//playback, NB
#endif
if (argc != 2)
{
printf("please run the command,such as mp3_player one.mp3.\n");
return -1;
}
fd = open("./test.wav", O_WRONLY | O_CREAT);
//leave enough room for header
lseek(fd, sizeof(struct wav_header), SEEK_SET);
/* install signal handler and begin to capture signal for close */
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
//init global variables
audio_player_ahw_dev_ubus = audio_hal_install();
if (audio_player_ahw_dev_ubus == NULL) {
printf("%s: audio_hal_install failed!\n", __FUNCTION__);
exit (-1);
}
rc = audio_player_ahw_dev_ubus->open_output_stream(audio_player_ahw_dev_ubus, 0,
audio_player_ahw_dev_ubus->get_supported_devices(audio_player_ahw_dev_ubus),
AUDIO_OUTPUT_FLAG_DIRECT, NULL, &stream_out, 0);
if (rc < 0) {
printf("%s: error opening output device. rc = %d\n", __FUNCTION__, rc);
goto bad_stream;
}
memset(&adapter_buf, 0x00, sizeof(adapter_buf));
//第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
if( (ret = my_init_ffmpeg(is, argv[1])) != 0) //1.1 初始化ffmpeg
{
printf("my_init_ffmpeg error");
return -1;
}
go_on_play = true;
while(go_on_play && (av_read_frame(is->pFormatCtx, packet) >= 0)) //1.2 循环读取mp3文件中的数据帧
{
if(packet->stream_index != is->sndindex)
continue;
if((ret = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
{
printf("file eof");
break;
}
if(got_frame <= 0) /* No data yet, get more frames */
continue;
//1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
if(NULL==is->swr_ctx)
{
if(is->swr_ctx != NULL)
swr_free(&is->swr_ctx);
//输入的声道个数
in_channel_nb = av_get_channel_layout_nb_channels(frame->channel_layout);
//输出的声道个数
out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
printf("frame: input channel: channnels=%d, format=%d, sample_rate=%d, nb_samples=%d.\n",
in_channel_nb, frame->format, frame->sample_rate, frame->nb_samples);
printf("frame: out channel: channels=%d, format=%d, sample_rate=%d.\n", out_channel_nb, out_sample_fmt, out_sample_rate);
is->swr_ctx = swr_alloc_set_opts(NULL, out_ch_layout, out_sample_fmt, out_sample_rate, av_get_default_channel_layout(in_channel_nb), frame->format, frame->sample_rate, 0, NULL);
if(is->swr_ctx == NULL)
{
printf("swr_ctx == NULL");
}
swr_init(is->swr_ctx);
}
converted_nb_samples = swr_convert(is->swr_ctx, out, AVCODEC_MAX_AUDIO_FRAME_SIZE * 2, (const uint8_t **)frame->data, frame->nb_samples);
file_data_size += converted_nb_samples;
//1.5 数据格式转换完成后就写到文件中
//sample bit is 16bits = 2Bytes
size = converted_nb_samples*out_channel_nb*2;
write(fd, (char *)(is->audio_buf), size);
/* adapter the length with pcm stream */
rc = set_adapter_buf((char *)(is->audio_buf), size);
if (rc < 0) {
printf("%s error.\n", __FUNCTION__);
goto end_pcm_stream;
}
len = 0;
memset(temp_buf, 0x00, sizeof(temp_buf));
rc = get_adapter_buf(temp_buf, &len);
if (rc < 0) {
printf("%s error.\n", __FUNCTION__);
continue;
//goto end_pcm_stream;
}
//printf("%s: len=%d.\n", __FUNCTION__, len);
if (len >= pcm_playback_size) {
/* write the PCM stream */
index = len / pcm_playback_size;
for (i=0; i<index; i++) {
//rc = write(fd, (char *)temp_buf+i*pcm_playback_size, pcm_playback_size);
rc = stream_out->write(stream_out, (char *)temp_buf+i*pcm_playback_size, pcm_playback_size);
if (rc < 0) {
printf("%s: error writing (child), pcm_playback_size=%d.\n", __FUNCTION__, pcm_playback_size);
goto end_pcm_stream;
} else if (rc < pcm_playback_size) {
printf("%s: wrote %d less than buffer size, pcm_playback_size=%d.\n", __FUNCTION__, rc, pcm_playback_size);
goto end_pcm_stream;
}
}
}
}
end_pcm_stream:
//sample bit is 16bits = 2Bytes
file_data_size *= (out_channel_nb*2);//(numSamples * wavFMT->numChannels * wavFMT->uiBitsPerSample) / 8
printf("file_data_size=%d, nb_samples=%d, converted_nb_samples=%d.\n", file_data_size, frame->nb_samples, converted_nb_samples);
//第2步添加上wav的头
//write header now all information is known
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = 1; //FORMAT_PCM;
header.num_channels = out_channel_nb; //Modem ONLY support mono recording
header.sample_rate = sample_rate; //44100, 8000, 16000
header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
header.block_align = header.num_channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
header.data_sz = file_data_size;
header.riff_sz = header.data_sz + sizeof(header) - 8;
lseek(fd, 0, SEEK_SET);
write(fd, &header, sizeof(struct wav_header));
printf("%s: sample_rate = %d, num_channels = %d!\n", __FUNCTION__, header.sample_rate, header.num_channels);
av_free_packet(packet);
av_free(frame);
avcodec_close(is->sndCodecCtx);
avformat_close_input(&is->pFormatCtx);
stream_out->common.standby(&stream_out->common);
audio_player_ahw_dev_ubus->close_output_stream(audio_player_ahw_dev_ubus, stream_out);
go_on_play = false;
bad_stream:
close(fd);
audio_hal_uninstall();
return 0;
}