886 lines
24 KiB
C
886 lines
24 KiB
C
|
/* pcmtest.c - native PCM test application
|
||
|
*
|
||
|
* Based on native pcm test application platform/system/extras/sound/playwav.c
|
||
|
*
|
||
|
* Copyright (C) 2008 The Android Open Source Project
|
||
|
* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdint.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <linux/msm_audio.h>
|
||
|
#include <pthread.h>
|
||
|
#include <errno.h>
|
||
|
#include "audiotest_def.h"
|
||
|
#include "equalizer.h"
|
||
|
|
||
|
#define DUAL_MIC_SOURCE 4
|
||
|
#define FRAME_NUM 128
|
||
|
|
||
|
const char *dev_file_name;
|
||
|
static char *next, *org_next;
|
||
|
static unsigned avail, org_avail;
|
||
|
static int quit, repeat;
|
||
|
static int rec_source;
|
||
|
int rec_stop = 1;
|
||
|
|
||
|
struct audiot_buf_config {
|
||
|
char *buf;
|
||
|
uint32_t head; /* next buffer app will write */
|
||
|
uint32_t tail; /* next buffer read() will read */
|
||
|
int fd;
|
||
|
int frame_available;
|
||
|
int buffer_size; /* pcm min buffer size */
|
||
|
uint32_t frame_count; /* total number of frames read */
|
||
|
pthread_mutex_t cond_lock;
|
||
|
pthread_mutex_t cmpl_lock;
|
||
|
pthread_mutex_t lock;
|
||
|
pthread_cond_t cond;
|
||
|
pthread_t thread;
|
||
|
};
|
||
|
|
||
|
void wait_for_frame(struct audiot_buf_config *buf_cfg)
|
||
|
{
|
||
|
pthread_mutex_lock(&buf_cfg->cond_lock);
|
||
|
while (!buf_cfg->frame_available && !rec_stop ) {
|
||
|
pthread_cond_wait(&buf_cfg->cond, &buf_cfg->cond_lock);
|
||
|
}
|
||
|
buf_cfg->frame_count--;
|
||
|
if(!buf_cfg->frame_count)
|
||
|
buf_cfg->frame_available = 0;
|
||
|
pthread_mutex_unlock(&buf_cfg->cond_lock);
|
||
|
}
|
||
|
|
||
|
void frame_available(struct audiot_buf_config *buf_cfg)
|
||
|
{
|
||
|
pthread_mutex_lock(&buf_cfg->cond_lock);
|
||
|
if(buf_cfg->frame_available == 0) {
|
||
|
buf_cfg->frame_available = 1;
|
||
|
}
|
||
|
buf_cfg->frame_count++;
|
||
|
pthread_cond_signal(&buf_cfg->cond);
|
||
|
pthread_mutex_unlock(&buf_cfg->cond_lock);
|
||
|
}
|
||
|
|
||
|
static int pcm_play(struct audtest_config *cfg, unsigned rate,
|
||
|
unsigned channels, int (*fill)(void *buf,
|
||
|
unsigned sz, void *cookie), void *cookie)
|
||
|
{
|
||
|
struct msm_audio_config config;
|
||
|
// struct msm_audio_stats stats;
|
||
|
unsigned n;
|
||
|
int sz;
|
||
|
char *buf;
|
||
|
int afd;
|
||
|
int cntW=0;
|
||
|
int ret = 0;
|
||
|
#ifdef AUDIOV2
|
||
|
unsigned short dec_id;
|
||
|
#endif
|
||
|
|
||
|
afd = open(dev_file_name, O_WRONLY);
|
||
|
|
||
|
if (afd < 0) {
|
||
|
perror("pcm_play: cannot open audio device");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
cfg->private_data = (void*) afd;
|
||
|
|
||
|
#ifdef AUDIOV2
|
||
|
if (ioctl(afd, AUDIO_GET_SESSION_ID, &dec_id)) {
|
||
|
perror("could not get decoder session id\n");
|
||
|
close(afd);
|
||
|
return -1;
|
||
|
}
|
||
|
#if defined(TARGET_USES_QCOM_MM_AUDIO)
|
||
|
if (devmgr_register_session(dec_id, DIR_RX) < 0) {
|
||
|
ret = -1;
|
||
|
goto exit;
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
if (ioctl(afd, AUDIO_GET_CONFIG, &config)) {
|
||
|
perror("could not get config");
|
||
|
ret = -1;
|
||
|
goto err_state;
|
||
|
}
|
||
|
|
||
|
config.channel_count = channels;
|
||
|
config.sample_rate = rate;
|
||
|
if (ioctl(afd, AUDIO_SET_CONFIG, &config)) {
|
||
|
perror("could not set config");
|
||
|
ret = -1;
|
||
|
goto err_state;
|
||
|
}
|
||
|
|
||
|
buf = (char*) malloc(sizeof(char) * config.buffer_size);
|
||
|
if (buf == NULL) {
|
||
|
perror("fail to allocate buffer\n");
|
||
|
ret = -1;
|
||
|
goto err_state;
|
||
|
}
|
||
|
|
||
|
printf("initiate_play: buffer_size=%d, buffer_count=%d\n", config.buffer_size,
|
||
|
config.buffer_count);
|
||
|
|
||
|
fprintf(stderr,"prefill\n");
|
||
|
for (n = 0; n < config.buffer_count; n++) {
|
||
|
if ((sz = fill(buf, config.buffer_size, cookie)) < 0)
|
||
|
break;
|
||
|
if (write(afd, buf, sz) != sz)
|
||
|
break;
|
||
|
}
|
||
|
cntW=cntW+config.buffer_count;
|
||
|
|
||
|
fprintf(stderr,"start playback\n");
|
||
|
if (ioctl(afd, AUDIO_START, 0) >= 0) {
|
||
|
for (;;) {
|
||
|
#if 0
|
||
|
if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0)
|
||
|
fprintf(stderr,"%10d\n", stats.out_bytes);
|
||
|
#endif
|
||
|
if (((sz = fill(buf, config.buffer_size, cookie)) < 0) || (quit == 1)) {
|
||
|
if ((repeat == 0) || (quit == 1)) {
|
||
|
printf(" fill return NON NULL, exit loop \n");
|
||
|
break;
|
||
|
} else {
|
||
|
printf("\nRepeat playback\n");
|
||
|
avail = org_avail;
|
||
|
next = org_next;
|
||
|
cntW = 0;
|
||
|
if(repeat > 0)
|
||
|
repeat--;
|
||
|
sleep(1);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
if (write(afd, buf, sz) != sz) {
|
||
|
printf(" write return not equal to sz, exit loop\n");
|
||
|
break;
|
||
|
} else {
|
||
|
cntW++;
|
||
|
printf(" pcm_play: repeat_count=%d cntW=%d\n", repeat, cntW);
|
||
|
}
|
||
|
}
|
||
|
printf("end of pcm play\n");
|
||
|
sleep(5);
|
||
|
} else {
|
||
|
printf("pcm_play: Unable to start driver\n");
|
||
|
}
|
||
|
free(buf);
|
||
|
err_state:
|
||
|
#if defined(TARGET_USES_QCOM_MM_AUDIO) && defined(AUDIOV2)
|
||
|
if (devmgr_unregister_session(dec_id, DIR_RX) < 0)
|
||
|
ret = -1;
|
||
|
exit:
|
||
|
#endif
|
||
|
close(afd);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
||
|
|
||
|
#define ID_RIFF 0x46464952
|
||
|
#define ID_WAVE 0x45564157
|
||
|
#define ID_FMT 0x20746d66
|
||
|
#define ID_DATA 0x61746164
|
||
|
|
||
|
#define FORMAT_PCM 1
|
||
|
|
||
|
struct wav_header {
|
||
|
uint32_t riff_id;
|
||
|
uint32_t riff_sz;
|
||
|
uint32_t riff_fmt;
|
||
|
uint32_t fmt_id;
|
||
|
uint32_t fmt_sz;
|
||
|
uint16_t audio_format;
|
||
|
uint16_t num_channels;
|
||
|
uint32_t sample_rate;
|
||
|
uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
|
||
|
uint16_t block_align; /* num_channels * bps / 8 */
|
||
|
uint16_t bits_per_sample;
|
||
|
uint32_t data_id;
|
||
|
uint32_t data_sz;
|
||
|
};
|
||
|
|
||
|
static int fill_buffer(void *buf, unsigned sz, void *cookie)
|
||
|
{
|
||
|
unsigned cpy_size = (sz < avail?sz:avail);
|
||
|
|
||
|
/* Below statement to remove warning for unused variable cookie,
|
||
|
but to keep function prototype intact */
|
||
|
(void) cookie;
|
||
|
|
||
|
if (avail == 0)
|
||
|
return -1;
|
||
|
|
||
|
memcpy(buf, next, cpy_size);
|
||
|
next += cpy_size;
|
||
|
avail -= cpy_size;
|
||
|
|
||
|
return cpy_size;
|
||
|
}
|
||
|
|
||
|
static int play_file(struct audtest_config *config,
|
||
|
unsigned rate, unsigned channels,
|
||
|
int fd, size_t count)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
next = (char*)malloc(count);
|
||
|
org_next = next;
|
||
|
printf(" play_file: count=%d,next=%p\n", count,next);
|
||
|
if (!next) {
|
||
|
fprintf(stderr,"could not allocate %d bytes\n", count);
|
||
|
return -1;
|
||
|
}
|
||
|
if (read(fd, next, count) != (ssize_t)count) {
|
||
|
fprintf(stderr,"could not read %d bytes\n", count);
|
||
|
return -1;
|
||
|
}
|
||
|
avail = count;
|
||
|
org_avail = avail;
|
||
|
ret = pcm_play(config, rate, channels, fill_buffer, 0);
|
||
|
free(org_next);
|
||
|
next = NULL;
|
||
|
org_next = NULL;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int wav_play(struct audtest_config *config)
|
||
|
{
|
||
|
|
||
|
struct wav_header hdr;
|
||
|
// unsigned rate, channels;
|
||
|
int fd;
|
||
|
|
||
|
if (config == NULL) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
fd = open(config->file_name, O_RDONLY);
|
||
|
if (fd < 0) {
|
||
|
fprintf(stderr, "playwav: cannot open '%s'\n", config->file_name);
|
||
|
return -1;
|
||
|
}
|
||
|
if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
|
||
|
fprintf(stderr, "playwav: cannot read header\n");
|
||
|
return -1;
|
||
|
}
|
||
|
fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n",
|
||
|
hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
|
||
|
hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
|
||
|
|
||
|
if ((hdr.riff_id != ID_RIFF) ||
|
||
|
(hdr.riff_fmt != ID_WAVE) ||
|
||
|
(hdr.fmt_id != ID_FMT)) {
|
||
|
fprintf(stderr, "playwav: '%s' is not a riff/wave file\n",
|
||
|
config->file_name);
|
||
|
return -1;
|
||
|
}
|
||
|
if ((hdr.audio_format != FORMAT_PCM) ||
|
||
|
(hdr.fmt_sz != 16)) {
|
||
|
fprintf(stderr, "playwav: '%s' is not pcm format\n", config->file_name);
|
||
|
return -1;
|
||
|
}
|
||
|
if (hdr.bits_per_sample != 16) {
|
||
|
fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", config->file_name);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return play_file(config, hdr.sample_rate, hdr.num_channels,
|
||
|
fd, hdr.data_sz);
|
||
|
}
|
||
|
|
||
|
|
||
|
void* pcmwrite_thread(void *arg)
|
||
|
{
|
||
|
struct audiot_buf_config *buf_cfg = (struct audiot_buf_config *)arg;
|
||
|
while(!rec_stop)
|
||
|
{
|
||
|
wait_for_frame(buf_cfg);
|
||
|
if (write(buf_cfg->fd,
|
||
|
&buf_cfg->buf[buf_cfg->tail * buf_cfg->buffer_size],
|
||
|
buf_cfg->buffer_size) != (ssize_t)buf_cfg->buffer_size) {
|
||
|
perror("cannot write buffer");
|
||
|
pthread_mutex_unlock(&buf_cfg->cmpl_lock);
|
||
|
return NULL;
|
||
|
}
|
||
|
pthread_mutex_lock(&buf_cfg->lock);
|
||
|
buf_cfg->tail = (buf_cfg->tail + 1) & (FRAME_NUM - 1);
|
||
|
pthread_mutex_unlock(&buf_cfg->lock);
|
||
|
|
||
|
}
|
||
|
pthread_mutex_unlock(&buf_cfg->cmpl_lock);
|
||
|
return NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
int wav_rec(struct audtest_config *config)
|
||
|
{
|
||
|
|
||
|
struct wav_header hdr;
|
||
|
char *buf;
|
||
|
struct msm_audio_config cfg;
|
||
|
struct audiot_buf_config *buf_cfg;
|
||
|
unsigned sz; //n;
|
||
|
int fd, afd;
|
||
|
unsigned total = 0;
|
||
|
struct audio_pvt_data *audio_data = (struct audio_pvt_data *)
|
||
|
config->private_data;
|
||
|
#ifdef AUDIOV2
|
||
|
unsigned short enc_id;
|
||
|
int device_id=-1;
|
||
|
const char *device = "a2dp_tx";
|
||
|
int a2dp_set = 0;
|
||
|
#endif
|
||
|
|
||
|
if ((config->channel_mode != 2) && (config->channel_mode != 1)) {
|
||
|
perror("invalid channel mode \n");
|
||
|
return -1;
|
||
|
} else {
|
||
|
switch (config->sample_rate) {
|
||
|
case 48000:
|
||
|
case 44100:
|
||
|
case 32000:
|
||
|
case 24000:
|
||
|
case 22050:
|
||
|
case 16000:
|
||
|
case 12000:
|
||
|
case 11025:
|
||
|
case 8000:
|
||
|
break;
|
||
|
default:
|
||
|
perror("invalid sample rate \n");
|
||
|
return -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hdr.riff_id = ID_RIFF;
|
||
|
hdr.riff_sz = 0;
|
||
|
hdr.riff_fmt = ID_WAVE;
|
||
|
hdr.fmt_id = ID_FMT;
|
||
|
hdr.fmt_sz = 16;
|
||
|
hdr.audio_format = FORMAT_PCM;
|
||
|
hdr.num_channels = config->channel_mode;
|
||
|
hdr.sample_rate = config->sample_rate;
|
||
|
hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
|
||
|
hdr.block_align = hdr.num_channels * 2;
|
||
|
hdr.bits_per_sample = 16;
|
||
|
hdr.data_id = ID_DATA;
|
||
|
hdr.data_sz = 0;
|
||
|
|
||
|
fd = open(config->file_name, O_CREAT | O_RDWR, 0666);
|
||
|
if (fd < 0) {
|
||
|
perror("cannot open output file");
|
||
|
return -1;
|
||
|
}
|
||
|
write(fd, &hdr, sizeof(hdr));
|
||
|
|
||
|
#if defined(AUDIOV2) || defined(AUDIO7X27A)
|
||
|
afd = open(dev_file_name, O_RDONLY);
|
||
|
if (afd < 0) {
|
||
|
perror("cannot open msm_pcm_in");
|
||
|
close(fd);
|
||
|
return -1;
|
||
|
}
|
||
|
#else
|
||
|
afd = open("/dev/msm_pcm_in", O_RDONLY);
|
||
|
if (afd < 0) {
|
||
|
perror("cannot open msm_pcm_in");
|
||
|
close(fd);
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifdef AUDIOV2
|
||
|
if (ioctl(afd, AUDIO_GET_SESSION_ID, &enc_id)) {
|
||
|
perror("could not get encoder session id\n");
|
||
|
close(fd);
|
||
|
close(afd);
|
||
|
return -1;
|
||
|
}
|
||
|
if(!strcmp(dev_file_name, "/dev/msm_a2dp_in"))
|
||
|
a2dp_set = 1;
|
||
|
if(!a2dp_set) {
|
||
|
printf("Routing to non A2DP\n");
|
||
|
if (devmgr_register_session(enc_id, DIR_TX) < 0) {
|
||
|
close(fd);
|
||
|
close(afd);
|
||
|
return -1;
|
||
|
}
|
||
|
} else {
|
||
|
device_id = msm_get_device(device);
|
||
|
printf("Routing to A2DP\n");
|
||
|
if (devmgr_enable_device(device_id, DIR_TX) < 0){
|
||
|
perror("could not enable TX device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
if (msm_route_stream(DIR_TX, enc_id, device_id, 1) < 0) {
|
||
|
perror("could not route stream to Device\n");
|
||
|
if (devmgr_disable_device(device_id, DIR_RX) < 0)
|
||
|
perror("could not disable device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
if (rec_source == DUAL_MIC_SOURCE) {
|
||
|
if (msm_set_dual_mic_config(enc_id, 1) < 0) {
|
||
|
perror("could not set dual mic config\n");
|
||
|
if (devmgr_disable_device(device_id, DIR_RX) < 0)
|
||
|
perror("could not disable device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
|
||
|
perror("cannot read audio config");
|
||
|
goto fail;
|
||
|
}
|
||
|
fprintf(stderr,"rec_buf_size = %d\n", audio_data->recsize);
|
||
|
cfg.buffer_size = audio_data->recsize;
|
||
|
cfg.channel_count = hdr.num_channels;
|
||
|
cfg.sample_rate = hdr.sample_rate;
|
||
|
|
||
|
sz = cfg.buffer_size;
|
||
|
if (sz > (cfg.buffer_size * FRAME_NUM)) {
|
||
|
fprintf(stderr, "buffer size %d too large\n", sz);
|
||
|
goto fail;
|
||
|
}
|
||
|
if (sz < 160) {
|
||
|
fprintf(stderr, "buffer size %d is small\n", sz);
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) {
|
||
|
perror("cannot write audio config");
|
||
|
goto fail;
|
||
|
}
|
||
|
buf_cfg = (struct audiot_buf_config *)malloc(sizeof(struct audiot_buf_config));
|
||
|
if(buf_cfg == NULL) {
|
||
|
fprintf(stderr,"\n buffer allocation failed \n");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
memset(buf_cfg,0,sizeof(struct audiot_buf_config));
|
||
|
|
||
|
buf_cfg->buf =(char *)malloc(cfg.buffer_size * FRAME_NUM);
|
||
|
if(buf_cfg->buf == NULL) {
|
||
|
|
||
|
fprintf(stderr,"\n buffer allocation failed \n");
|
||
|
goto fail;
|
||
|
}
|
||
|
rec_stop = 0;
|
||
|
buf_cfg->buffer_size = sz;
|
||
|
buf_cfg->fd = fd;
|
||
|
buf = buf_cfg->buf;
|
||
|
pthread_cond_init(&buf_cfg->cond, 0);
|
||
|
pthread_mutex_init(&buf_cfg->cond_lock, 0);
|
||
|
pthread_mutex_init(&buf_cfg->cmpl_lock, 0);
|
||
|
pthread_mutex_init(&buf_cfg->lock, 0);
|
||
|
pthread_create( &buf_cfg->thread, NULL,
|
||
|
pcmwrite_thread, (void*) buf_cfg);
|
||
|
|
||
|
#ifdef AUDIOV2
|
||
|
/* Record form voice link */
|
||
|
if (rec_source <= VOC_REC_BOTH ) {
|
||
|
|
||
|
if (ioctl(afd, AUDIO_SET_INCALL, &rec_source)) {
|
||
|
perror("Error: AUDIO_SET_INCALL failed");
|
||
|
goto fail;
|
||
|
}
|
||
|
printf("rec source = 0x%8x\n", rec_source);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (ioctl(afd, AUDIO_START, 0) < 0) {
|
||
|
perror("cannot start audio");
|
||
|
goto fail;
|
||
|
}
|
||
|
fprintf(stderr,"\n*** RECORDING IN PROGRESS ***\n");
|
||
|
while(!rec_stop) {
|
||
|
if (read(afd, &buf[buf_cfg->head * sz], sz) != (ssize_t)sz) {
|
||
|
perror("cannot read buffer");
|
||
|
rec_stop = 1;
|
||
|
frame_available(buf_cfg);
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
pthread_mutex_lock(&buf_cfg->lock);
|
||
|
buf_cfg->head = (buf_cfg->head + 1) & (FRAME_NUM - 1);
|
||
|
|
||
|
/* If overflow, move the tail index foward. */
|
||
|
if (buf_cfg->head == buf_cfg->tail)
|
||
|
{
|
||
|
buf_cfg->tail = (buf_cfg->tail + 1) & (FRAME_NUM - 1);
|
||
|
fprintf(stderr,"\n***BUFFER OVERFLOW***");
|
||
|
rec_stop = 1;
|
||
|
pthread_mutex_unlock(&buf_cfg->lock);
|
||
|
|
||
|
frame_available(buf_cfg);
|
||
|
goto done;
|
||
|
}
|
||
|
pthread_mutex_unlock(&buf_cfg->lock);
|
||
|
|
||
|
frame_available(buf_cfg);
|
||
|
total += sz;
|
||
|
}
|
||
|
done:
|
||
|
close(afd);
|
||
|
/* wait for pcm writer thread to exit */
|
||
|
pthread_mutex_lock(&buf_cfg->cmpl_lock);
|
||
|
|
||
|
/* update lengths in header */
|
||
|
hdr.data_sz = total;
|
||
|
hdr.riff_sz = total + 8 + 16 + 8;
|
||
|
lseek(fd, 0, SEEK_SET);
|
||
|
write(fd, &hdr, sizeof(hdr));
|
||
|
close(fd);
|
||
|
pthread_cond_destroy(&buf_cfg->cond);
|
||
|
pthread_mutex_destroy(&buf_cfg->cond_lock);
|
||
|
pthread_mutex_destroy(&buf_cfg->lock);
|
||
|
pthread_mutex_destroy(&buf_cfg->cmpl_lock);
|
||
|
#ifdef AUDIOV2
|
||
|
if(!a2dp_set) {
|
||
|
printf("Derouting from non A2DP\n");
|
||
|
if (devmgr_unregister_session(enc_id, DIR_TX) < 0){
|
||
|
perror("could not unregister encode session\n");
|
||
|
}
|
||
|
} else {
|
||
|
printf("Derouting from A2DP\n");
|
||
|
if (devmgr_disable_device(device_id, DIR_TX) < 0){
|
||
|
perror("could not enable TX device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
if (msm_route_stream(DIR_TX, enc_id, device_id, 0) < 0) {
|
||
|
perror("could not route stream to Device\n");
|
||
|
if (devmgr_disable_device(device_id, DIR_RX) < 0)
|
||
|
perror("could not disable device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return 0;
|
||
|
|
||
|
fail:
|
||
|
close(afd);
|
||
|
close(fd);
|
||
|
#ifdef AUDIOV2
|
||
|
if(!a2dp_set) {
|
||
|
printf("Derouting from non A2DP\n");
|
||
|
if (devmgr_unregister_session(enc_id, DIR_TX) < 0){
|
||
|
perror("could not unregister encode session\n");
|
||
|
}
|
||
|
} else {
|
||
|
device_id = msm_get_device(device);
|
||
|
printf("De Routing to A2DP\n");
|
||
|
if (devmgr_enable_device(device_id, DIR_TX) < 0){
|
||
|
perror("could not enable TX device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
if (msm_route_stream(DIR_TX, enc_id, device_id, 1) < 0) {
|
||
|
perror("could not route stream to Device\n");
|
||
|
if (devmgr_disable_device(device_id, DIR_RX) < 0)
|
||
|
perror("could not disable device\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
unlink(config->file_name);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
void* playpcm_thread(void* arg) {
|
||
|
struct audiotest_thread_context *context =
|
||
|
(struct audiotest_thread_context*) arg;
|
||
|
int ret_val;
|
||
|
|
||
|
ret_val = wav_play(&context->config);
|
||
|
free_context(context);
|
||
|
pthread_exit((void*) ret_val);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int pcmplay_read_params(void) {
|
||
|
struct audiotest_thread_context *context;
|
||
|
char *token;
|
||
|
int ret_val = 0;
|
||
|
|
||
|
if ((context = get_free_context()) == NULL) {
|
||
|
ret_val = -1;
|
||
|
} else {
|
||
|
context->config.file_name = "/data/data.wav";
|
||
|
dev_file_name = "/dev/msm_pcm_out";
|
||
|
repeat = 0;
|
||
|
quit = 0;
|
||
|
|
||
|
token = strtok(NULL, " ");
|
||
|
|
||
|
while (token != NULL) {
|
||
|
if (!memcmp(token,"-id=", (sizeof("-id=")-1))) {
|
||
|
context->cxt_id = atoi(&token[sizeof("-id=") - 1]);
|
||
|
} else if (!memcmp(token, "-dev=",
|
||
|
(sizeof("-dev=") - 1))) {
|
||
|
dev_file_name = token + (sizeof("-dev=")-1);
|
||
|
} else if (!memcmp(token, "-repeat=",
|
||
|
(sizeof("-repeat=") - 1))) {
|
||
|
repeat = atoi(&token[sizeof("-repeat=") - 1]);
|
||
|
if (repeat == 0)
|
||
|
repeat = -1;
|
||
|
else
|
||
|
repeat--;
|
||
|
} else {
|
||
|
context->config.file_name = token;
|
||
|
}
|
||
|
token = strtok(NULL, " ");
|
||
|
}
|
||
|
context->type = AUDIOTEST_TEST_MOD_PCM_DEC;
|
||
|
pthread_create( &context->thread, NULL,
|
||
|
playpcm_thread, (void*) context);
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
|
||
|
}
|
||
|
|
||
|
void* recpcm_thread(void* arg) {
|
||
|
struct audiotest_thread_context *context =
|
||
|
(struct audiotest_thread_context*) arg;
|
||
|
int ret_val;
|
||
|
|
||
|
ret_val = wav_rec(&context->config);
|
||
|
free_context(context);
|
||
|
pthread_exit((void*) ret_val);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int pcmrec_read_params(void) {
|
||
|
struct audiotest_thread_context *context;
|
||
|
char *token;
|
||
|
int ret_val = 0;
|
||
|
|
||
|
if ((context = get_free_context()) == NULL) {
|
||
|
ret_val = -1;
|
||
|
} else {
|
||
|
context->config.sample_rate = 8000;
|
||
|
context->config.file_name = "/data/record.wav";
|
||
|
dev_file_name = "/dev/msm_pcm_in";
|
||
|
context->config.channel_mode = 1;
|
||
|
context->type = AUDIOTEST_TEST_MOD_PCM_ENC;
|
||
|
rec_source = 3;
|
||
|
struct audio_pvt_data *audio_data;
|
||
|
audio_data = (struct audio_pvt_data *)
|
||
|
malloc(sizeof(struct audio_pvt_data));
|
||
|
|
||
|
if(!audio_data) {
|
||
|
printf("error allocating audio instance structure \n");
|
||
|
free_context(context);
|
||
|
ret_val = -1;
|
||
|
} else {
|
||
|
|
||
|
audio_data->recsize = 2048;
|
||
|
token = strtok(NULL, " ");
|
||
|
while (token != NULL) {
|
||
|
printf("%s \n", token);
|
||
|
if (!memcmp(token,"-rate=", (sizeof("-rate=") - 1))) {
|
||
|
context->config.sample_rate =
|
||
|
atoi(&token[sizeof("-rate=") - 1]);
|
||
|
} else if (!memcmp(token,"-cmode=", (sizeof("-cmode=") - 1))) {
|
||
|
context->config.channel_mode =
|
||
|
atoi(&token[sizeof("-cmode=") - 1]);
|
||
|
} else if (!memcmp(token,"-recbufsize=", (sizeof("-recbufsize=") - 1))) {
|
||
|
audio_data->recsize = atoi(&token[sizeof("-recbufsize=") - 1]);
|
||
|
} else if (!memcmp(token,"-id=", (sizeof("-id=") - 1))) {
|
||
|
context->cxt_id = atoi(&token[sizeof("-id=") - 1]);
|
||
|
} else if (!memcmp(token, "-dev=",
|
||
|
(sizeof("-dev=") - 1))) {
|
||
|
dev_file_name = token + (sizeof("-dev=")-1);
|
||
|
} else if (!memcmp(token, "-src=", (sizeof("-src=") - 1))) {
|
||
|
rec_source = atoi(&token[sizeof("-src=") - 1]);
|
||
|
} else {
|
||
|
context->config.file_name = token;
|
||
|
}
|
||
|
token = strtok(NULL, " ");
|
||
|
}
|
||
|
context->config.private_data = (struct audio_pvt_data *) audio_data;
|
||
|
printf("%s:sample_rate=%d channel_mode=%d, recbufsize = %d\n", __FUNCTION__,
|
||
|
context->config.sample_rate, context->config.channel_mode,
|
||
|
audio_data->recsize);
|
||
|
pthread_create( &context->thread, NULL, recpcm_thread, (void*) context);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
int pcm_play_control_handler(void* private_data) {
|
||
|
int drvfd , ret_val = 0;
|
||
|
int volume;
|
||
|
char *token;
|
||
|
#if defined(TARGET_USES_QCOM_MM_AUDIO) && defined(AUDIOV2)
|
||
|
int eq_preset;
|
||
|
#endif
|
||
|
|
||
|
token = strtok(NULL, " ");
|
||
|
if ((private_data != NULL) &&
|
||
|
(token != NULL)) {
|
||
|
drvfd = (int) private_data;
|
||
|
if(!memcmp(token,"-cmd=", (sizeof("-cmd=") -1))) {
|
||
|
token = &token[sizeof("-cmd=") - 1];
|
||
|
printf("%s: cmd %s\n", __FUNCTION__, token);
|
||
|
#if defined(TARGET_USES_QCOM_MM_AUDIO) && defined(AUDIOV2)
|
||
|
if (!strcmp(token, "volume")) {
|
||
|
int rc;
|
||
|
unsigned short dec_id;
|
||
|
token = strtok(NULL, " ");
|
||
|
if (!memcmp(token, "-value=",
|
||
|
(sizeof("-value=") - 1))) {
|
||
|
volume = atoi(&token[sizeof("-value=") - 1]);
|
||
|
if (ioctl(drvfd, AUDIO_GET_SESSION_ID, &dec_id)) {
|
||
|
perror("could not get decoder session id\n");
|
||
|
} else {
|
||
|
printf("session %d - volume %d \n", dec_id, volume);
|
||
|
if ((volume >= 0) && (volume <= 100)) {
|
||
|
rc = msm_set_volume(dec_id, volume);
|
||
|
printf("session volume result %d\n", rc);
|
||
|
} else
|
||
|
printf("session volume out of range\n");
|
||
|
}
|
||
|
}
|
||
|
} else if (!strcmp(token, "eq")) {
|
||
|
token = strtok(NULL, " ");
|
||
|
if (!memcmp(token, "-preset=",
|
||
|
(sizeof("-preset=") - 1))) {
|
||
|
eq_preset = atoi(&token[sizeof("-preset=") - 1]);
|
||
|
if ((eq_preset >= 0) && (eq_preset < MAX_PRESETS))
|
||
|
#ifdef QDSP6V2
|
||
|
set_pcm_default_eq_values(drvfd, eq_preset);
|
||
|
#else
|
||
|
printf("not supported\n");
|
||
|
#endif
|
||
|
else {
|
||
|
printf("Wrong preset:%d Check command: \
|
||
|
for supported preset values\n", eq_preset);
|
||
|
printf("mm-audio-native-test -format playpcm\n");
|
||
|
}
|
||
|
}
|
||
|
} else if (!strcmp(token, "stop")) {
|
||
|
quit = 1;
|
||
|
printf("quit session\n");
|
||
|
}
|
||
|
#else
|
||
|
if (!strcmp(token, "pause")) {
|
||
|
ioctl(drvfd, AUDIO_PAUSE, 1);
|
||
|
} else if (!strcmp(token, "resume")) {
|
||
|
ioctl(drvfd, AUDIO_PAUSE, 0);
|
||
|
} else if (!strcmp(token, "volume")) {
|
||
|
token = strtok(NULL, " ");
|
||
|
if (!memcmp(token, "-value=",
|
||
|
(sizeof("-value=") - 1))) {
|
||
|
volume =
|
||
|
atoi(&token[sizeof("-value=") - 1]);
|
||
|
ioctl(drvfd, AUDIO_SET_VOLUME, volume);
|
||
|
printf("volume:%d\n", volume);
|
||
|
}
|
||
|
} else if (!strcmp(token, "stop")) {
|
||
|
quit = 1;
|
||
|
printf("quit session\n");
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
} else {
|
||
|
ret_val = -1;
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
int pcm_rec_control_handler(void* private_data) {
|
||
|
int /* drvfd ,*/ ret_val = 0;
|
||
|
char *token;
|
||
|
|
||
|
token = strtok(NULL, " ");
|
||
|
if ((private_data != NULL) &&
|
||
|
(token != NULL)) {
|
||
|
/* drvfd = (int) private_data */
|
||
|
if(!memcmp(token,"-cmd=", (sizeof("-cmd=") -1))) {
|
||
|
token = &token[sizeof("-cmd=") - 1];
|
||
|
printf("%s: cmd %s\n", __FUNCTION__, token);
|
||
|
if (!strcmp(token, "stop")) {
|
||
|
rec_stop = 1;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
ret_val = -1;
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
const char *pcmplay_help_txt =
|
||
|
"Play PCM file: type \n\
|
||
|
echo \"playpcm path_of_file -id=xxx -repeat=x -dev=/dev/msm_pcm_dec or msm_pcm_out\" > tmp/audio_test \n\
|
||
|
Repeat 'x' no. of times, repeat infinitely if repeat = 0\n\
|
||
|
Sample rate of PCM file <= 48000 \n\
|
||
|
Bits per sample = 16 bits \n\
|
||
|
Supported control command: pause, flush, volume, stop, equalizer\n\
|
||
|
examples: \n\
|
||
|
echo \"control_cmd -id=xxx -cmd=eq -preset=yyyy\" > %s \n\
|
||
|
0 - BLANK \n\
|
||
|
1 - CLUB \n\
|
||
|
2 - DANCE \n\
|
||
|
3 - FULLBASS \n\
|
||
|
4 - FULLBASSTREBLE \n\
|
||
|
5 - FULLTREBLE \n\
|
||
|
6 - LAPTOP \n\
|
||
|
7 - LARGEHALL \n\
|
||
|
8 - LIVE \n\
|
||
|
9 - PARTY \n\
|
||
|
10 - POP \n\
|
||
|
11 - REGGAE \n\
|
||
|
12 - ROCK \n\
|
||
|
13 - SKA \n\
|
||
|
14 - SOFT \n\
|
||
|
15 - SOFTROCK \n\
|
||
|
16 - TECHNO \n";
|
||
|
|
||
|
|
||
|
void pcmplay_help_menu(void) {
|
||
|
printf("%s\n", pcmplay_help_txt);
|
||
|
}
|
||
|
|
||
|
const char *pcmrec_help_txt =
|
||
|
"Record pcm file: type \n\
|
||
|
echo \"recpcm path_of_file -rate=xxx -cmode=x -recbufsize=x -id=xxx -src=x -dev=/dev/msm_pcm_in or msm_a2dp_in\" > tmp/audio_test \n\
|
||
|
sample rate: 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 \n\
|
||
|
src: 0 - Uplink 1 - Downlink, 2 - UL/DL, 3 - Mic 4 - Dual MIC\n\
|
||
|
channel mode: 1 or 2 \n\
|
||
|
recbufsize(recording buffer size): value greater than 160 and a multiple of 4 for 8k, default is 2048 \n\
|
||
|
(512,1024 or 2048) * channel mode for 7x30, default is 2048 \n\
|
||
|
Supported control command: stop\n ";
|
||
|
|
||
|
void pcmrec_help_menu(void) {
|
||
|
printf("%s\n", pcmrec_help_txt);
|
||
|
}
|