332 lines
9.3 KiB
C
Executable File
332 lines
9.3 KiB
C
Executable File
/*
|
|
* Copyright 2022 Rockchip Electronics Co. LTD
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
//#include <utils/Log.h>
|
|
#include <errno.h>
|
|
#include "bitstream/audio_bitstream.h"
|
|
#include "bitstream/audio_bitstream_manager.h"
|
|
#include "alsa_audio.h"
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include "asoundlib.h"
|
|
|
|
#ifdef LOG_TAG
|
|
#undef LOG_TAG
|
|
#endif
|
|
#define LOG_TAG "bitstreamTest"
|
|
|
|
#define ALOGD printf
|
|
#define ALOGE printf
|
|
|
|
#define MODE_LPCM 0
|
|
#define MODE_NLPCM 1
|
|
#define MODE_HBR 2
|
|
|
|
uint64_t getRelativeUs() {
|
|
struct timespec time = {0, 0};
|
|
clock_gettime(CLOCK_MONOTONIC, &time);
|
|
return (uint64_t)time.tv_sec * 1000000 + (uint64_t)time.tv_nsec / 1000; /* microseconds */
|
|
}
|
|
|
|
uint64_t getRelativeMs() {
|
|
return getRelativeUs()/1000; /* milliseconds */
|
|
}
|
|
|
|
struct pcm* openSoundCard(int card, int device, struct pcm_config *config) {
|
|
struct pcm *sound = pcm_open(card, device, PCM_OUT | PCM_MONOTONIC, config);
|
|
if (sound && !pcm_is_ready(sound)) {
|
|
ALOGE("%s open sound card failed: %s, card = %d, device = %d",
|
|
__FUNCTION__, pcm_get_error(sound),card, device);
|
|
pcm_close(sound);
|
|
return NULL;
|
|
}
|
|
return sound;
|
|
}
|
|
|
|
static int set_hdmi_mode(int card, int mode) {
|
|
int ret = 0;
|
|
struct mixer* pMixer = mixer_open_legacy((unsigned)card);
|
|
if (!pMixer) {
|
|
ALOGE("mMixer is a null point %s %d,CARD = %d\n",
|
|
__func__, __LINE__, card);
|
|
return -1;
|
|
}
|
|
|
|
struct mixer_ctl *pctl = mixer_get_control(pMixer, "AUDIO MODE", 0);
|
|
if (pctl != NULL) {
|
|
ALOGD("set mixer audio_mode is %d for drm\n", mode);
|
|
switch (mode) {
|
|
case MODE_HBR:
|
|
ret = mixer_ctl_set_val(pctl , MODE_HBR);
|
|
break;
|
|
case MODE_NLPCM:
|
|
ret = mixer_ctl_set_val(pctl , MODE_NLPCM);
|
|
break;
|
|
default:
|
|
ret = mixer_ctl_set_val(pctl , MODE_LPCM);
|
|
break;
|
|
}
|
|
|
|
if (ret != 0) {
|
|
ALOGE("set_controls() can not set ctl!\n");
|
|
mixer_close_legacy(pMixer);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
mixer_close_legacy(pMixer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int gSoundCard = -1;
|
|
static void signal_handler(int sig) {
|
|
if (gSoundCard != -1) {
|
|
// set pcm mode to hdmi
|
|
#ifndef IEC958_FORAMT
|
|
set_hdmi_mode(gSoundCard, MODE_LPCM);
|
|
#endif
|
|
gSoundCard = -1;
|
|
}
|
|
ALOGD("Interrupt sig = %d received bitstream test exit\n", sig);
|
|
exit(sig);
|
|
}
|
|
|
|
/*
|
|
* test cmd:
|
|
* bitstream_test -i /data/ac3_iec61937.bin -D 0 -d 0 -r 48000 -c 2 -f s24
|
|
* bitstream_test -i /data/ac3_iec61937.bin -D 0 -d 0 -r 48000 -c 2 -f s16
|
|
* bitstream_test -i /data/ac3_iec61937.bin -D 0 -d 0 -r 48000 -c 2 -f s958
|
|
*/
|
|
int main(int argc, char **argv) {
|
|
if (argc < 2) {
|
|
ALOGE("Usage: %s [-i file] [-D card] [-d device] [-r samplerate]"
|
|
" [-c channels] \n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
signal(SIGINT, signal_handler);
|
|
signal(SIGTERM, signal_handler);
|
|
signal(SIGABRT, signal_handler);
|
|
|
|
int card = -1;
|
|
int device = -1;
|
|
int samplerate = 0;
|
|
int channels = 0;
|
|
int format = PCM_FORMAT_IEC958_SUBFRAME_LE;
|
|
int peroid = 0;
|
|
|
|
int size = 0;
|
|
int mode = MODE_NLPCM;
|
|
uint64_t time1, time2, startTime;
|
|
uint64_t total = 0;
|
|
char path[256] = {0};
|
|
rk_bistream* bs = NULL;
|
|
|
|
struct pcm_config config = {
|
|
.channels = 2,
|
|
.rate = 48000,
|
|
.period_size = 1024,
|
|
.period_count = 4,
|
|
.format = PCM_FORMAT_IEC958_SUBFRAME_LE,
|
|
};
|
|
|
|
// parse argments
|
|
while (*argv) {
|
|
if (strcmp(*argv, "-d") == 0) { // index of device card
|
|
argv++;
|
|
if (*argv)
|
|
device = atoi(*argv);
|
|
} else if (strcmp(*argv, "-D") == 0) { // index of sound card
|
|
argv++;
|
|
if (*argv)
|
|
card = atoi(*argv);
|
|
} else if (strcmp(*argv, "-i") == 0) { // test input file(audio format=IEC61937)
|
|
argv++;
|
|
if (*argv) {
|
|
ALOGD("path = %s", *argv);
|
|
snprintf(path, sizeof(path), "%s", *argv);
|
|
}
|
|
} else if (strcmp(*argv, "-r") == 0) { // samplerate
|
|
argv++;
|
|
if (*argv) {
|
|
samplerate = atoi(*argv);
|
|
}
|
|
} else if (strcmp(*argv, "-c") == 0) { // channels
|
|
argv++;
|
|
if (*argv) {
|
|
channels = atoi(*argv);
|
|
if (channels > 2) {
|
|
mode = MODE_HBR;
|
|
}
|
|
}
|
|
} else if (strcmp(*argv, "-p") == 0) { // peroid size of sound card
|
|
argv++;
|
|
if (*argv) {
|
|
peroid = atoi(*argv);
|
|
}
|
|
} else if (strcmp(*argv, "-f") == 0) { // format to open sound card
|
|
argv++;
|
|
if (!strcmp(*argv, "s16")) { // spdif and rk616 or rk3128
|
|
format = PCM_FORMAT_S16_LE;
|
|
} else if (!strcmp(*argv, "s24")) { // hdmi
|
|
format = PCM_FORMAT_S24_LE;
|
|
} else if (!strcmp(*argv, "s958")) { // hdmi kernel5.1 and later version
|
|
format = PCM_FORMAT_IEC958_SUBFRAME_LE;
|
|
} else {
|
|
ALOGD("%s: format = %s not support", __FUNCTION__, *argv);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (*argv)
|
|
argv++;
|
|
}
|
|
|
|
// check input format
|
|
#ifdef IEC958_FORAMT
|
|
if (format == PCM_FORMAT_S24_LE) {
|
|
ALOGD("%s: PCM_FORMAT_S24_LE not support, using s958", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
#else
|
|
if (format == PCM_FORMAT_IEC958_SUBFRAME_LE) {
|
|
ALOGD("%s: PCM_FORMAT_IEC958_SUBFRAME_LE not support, using s24", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
int period_size = (peroid != 0) ? peroid : samplerate/100; // 10ms
|
|
config.period_size = period_size;
|
|
config.rate = samplerate;
|
|
config.channels = channels;
|
|
config.format = format;
|
|
gSoundCard = card;
|
|
|
|
ALOGD("play file = %s\n", path);
|
|
ALOGD("samplerate = %d, channels = %d, format = %d\n", config.rate, config.channels, config.format);
|
|
ALOGD("period_size = %d, period_count = %d\n", config.period_size, config.period_count);
|
|
|
|
#ifndef IEC958_FORAMT
|
|
// set hdmi's mode, the hdmi drvier before kernel5.1 will read it
|
|
set_hdmi_mode(card, mode);
|
|
#endif
|
|
|
|
// open sound card
|
|
struct pcm *sound = openSoundCard(card, device, &config);
|
|
if (sound == NULL) {
|
|
ALOGE("%s:%d open sound = %d device = %d fail\n", __FUNCTION__, __LINE__, card, device);
|
|
return -1;
|
|
}
|
|
|
|
int buffer_size = period_size*sizeof(short)*channels;
|
|
ALOGD("%s:%d buffer_size = %d\n", __FUNCTION__, __LINE__, buffer_size);
|
|
char *inBuffer = malloc(buffer_size);
|
|
char *outBuffer = NULL;
|
|
int inSize = 0;
|
|
int outSize = 0;
|
|
int ret = 0;
|
|
|
|
FILE *file = fopen(path, "rb");
|
|
if (file == NULL) {
|
|
ALOGE("%s:%d open %s fail, %s\n", __FUNCTION__, __LINE__, path, strerror(errno));
|
|
goto EXIT;
|
|
}
|
|
|
|
if (config.format != PCM_FORMAT_S16_LE) {
|
|
bs = bitstream_init(config.format, samplerate, channels);
|
|
if (bs == NULL) {
|
|
ALOGE("%s:%d bitstream_init fail\n", __FUNCTION__, __LINE__);
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
int counter = 0;
|
|
time1 = getRelativeMs();
|
|
startTime = time2 = time1;
|
|
|
|
while (1) {
|
|
// read IEC61937 data
|
|
inSize = fread(inBuffer, 1, buffer_size, file);
|
|
if (inSize <= 0) {
|
|
ALOGE("%s:%d read file eos\n", __FUNCTION__, __LINE__);
|
|
break;
|
|
}
|
|
|
|
counter ++;
|
|
total += inSize;
|
|
outSize = 0;
|
|
|
|
// spdif/RK616/RK3128 use S16_LE
|
|
if (config.format == PCM_FORMAT_S16_LE) {
|
|
outSize = inSize;
|
|
outBuffer = inBuffer;
|
|
} else {
|
|
// convert IEC61937 to IEC60958
|
|
bitstream_encode(bs, inBuffer, inSize, &outBuffer, &outSize);
|
|
}
|
|
|
|
if (outSize > 0) {
|
|
ret = pcm_write(sound, (void *)outBuffer, outSize);
|
|
if (ret != 0) {
|
|
ALOGE("%s: %d write data fail\n", __FUNCTION__, __LINE__);
|
|
}
|
|
}
|
|
|
|
// for debug print data every 1 second
|
|
time2 = getRelativeMs();
|
|
if (time2 - time1 >= 1000ll) {
|
|
ALOGD("total ms = %lld, total size = %lld, counter = %d\n", time2-startTime, total, counter);
|
|
time1 = time2;
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
if (bs != NULL) {
|
|
bitstream_destory(&bs);
|
|
}
|
|
|
|
if (inBuffer != NULL) {
|
|
free(inBuffer);
|
|
inBuffer = NULL;
|
|
}
|
|
|
|
if (file != NULL) {
|
|
fclose(file);
|
|
file = NULL;
|
|
}
|
|
|
|
if (sound != NULL) {
|
|
pcm_close(sound);
|
|
sound = NULL;
|
|
}
|
|
|
|
#ifndef IEC958_FORAMT
|
|
if (card != -1) {
|
|
// set pcm mode to hdmi
|
|
set_hdmi_mode(card, MODE_LPCM);
|
|
}
|
|
#endif
|
|
|
|
gSoundCard = -1;
|
|
ALOGD("bitstream test exit\n");
|
|
return 0;
|
|
}
|
|
|