From 028bb98fc15f871d4bca0a82b62c9fbc3b1a96a8 Mon Sep 17 00:00:00 2001 From: tytung Date: Tue, 29 Mar 2011 00:09:00 +0800 Subject: [PATCH] audio: added Two-way call recording (Credit to avs333) Applied snq-'s modified patch below and fixed the compilation error on HD2 by tytung http://forum.xda-developers.com/showpost.php?p=12316760&postcount=154 --- arch/arm/mach-msm/Kconfig | 5 ++ arch/arm/mach-msm/qdsp6_1550/pcm_in.c | 103 ++++++++++++++++++++++++- arch/arm/mach-msm/qdsp6_1550/q6audio.c | 61 ++++++++++++++- 3 files changed, 163 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 7c69be36..e9fe1902 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -913,6 +913,11 @@ config QSD_AUDIO help Provides PCM, MP3, and AAC audio playback. +config QSD_AUDIO_CALLREC + bool "Call recording support [avs333]" + depends on QSD_AUDIO + default n + config VIRTUAL_KPANIC_PSIZE depends on VIRTUAL_KPANIC_PARTITION int "Default kpanic partition size" diff --git a/arch/arm/mach-msm/qdsp6_1550/pcm_in.c b/arch/arm/mach-msm/qdsp6_1550/pcm_in.c index c580527f..ad84f53f 100644 --- a/arch/arm/mach-msm/qdsp6_1550/pcm_in.c +++ b/arch/arm/mach-msm/qdsp6_1550/pcm_in.c @@ -26,18 +26,38 @@ #include -#define BUFSZ (4096) -#define DMASZ (BUFSZ * 2) +#define BUFSZ (256) +#ifdef CONFIG_QSD_AUDIO_CALLREC +struct msm_voicerec_mode { + uint32_t rec_mode; +}; + +#define AUDIO_SET_INCALL _IOW(AUDIO_IOCTL_MAGIC, 19, struct msm_voicerec_mode) +#define AUDIO_FLAG_INCALL_MIXED 2 + +struct pcm { + struct audio_client *ac; + uint32_t sample_rate; + uint32_t channel_count; + uint32_t buffer_size; + uint32_t rec_mode; +}; +#else static DEFINE_MUTEX(pcm_in_lock); static uint32_t sample_rate = 8000; static uint32_t channel_count = 1; +static uint32_t buffer_size = BUFSZ; static int pcm_in_opened = 0; +#endif void audio_client_dump(struct audio_client *ac); static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { +#ifdef CONFIG_QSD_AUDIO_CALLREC + struct pcm *pcm = file->private_data; +#endif int rc = 0; switch (cmd) { @@ -61,16 +81,30 @@ static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } +#ifndef CONFIG_QSD_AUDIO_CALLREC mutex_lock(&pcm_in_lock); if (file->private_data) { +#else + if (pcm->ac) { +#endif rc = -EBUSY; } else { +#ifdef CONFIG_QSD_AUDIO_CALLREC + pcm->ac = q6audio_open_pcm(pcm->buffer_size, + pcm->sample_rate, pcm->channel_count, + pcm->rec_mode, acdb_id); + if (!pcm->ac) + rc = -ENOMEM; +#else file->private_data = q6audio_open_pcm( BUFSZ, sample_rate, channel_count, AUDIO_FLAG_READ, acdb_id); if (!file->private_data) rc = -ENOMEM; +#endif } +#ifndef CONFIG_QSD_AUDIO_CALLREC mutex_unlock(&pcm_in_lock); +#endif break; } case AUDIO_STOP: @@ -83,16 +117,45 @@ static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rc = -EFAULT; break; } +#ifdef CONFIG_QSD_AUDIO_CALLREC + pcm->sample_rate = config.sample_rate; + pcm->channel_count = config.channel_count; + pcm->buffer_size = config.buffer_size; +#else sample_rate = config.sample_rate; channel_count = config.channel_count; + buffer_size = config.buffer_size; +#endif break; } +#ifdef CONFIG_QSD_AUDIO_CALLREC + case AUDIO_SET_INCALL: { + struct msm_voicerec_mode voicerec_mode; + if (copy_from_user(&voicerec_mode, (void *)arg, + sizeof(struct msm_voicerec_mode))) + return -EFAULT; + if (voicerec_mode.rec_mode != AUDIO_FLAG_READ && + voicerec_mode.rec_mode != AUDIO_FLAG_INCALL_MIXED) { + pcm->rec_mode = AUDIO_FLAG_READ; + pr_err("invalid rec_mode\n"); + rc = -EINVAL; + } else + pcm->rec_mode = voicerec_mode.rec_mode; + break; + } +#endif case AUDIO_GET_CONFIG: { struct msm_audio_config config; - config.buffer_size = BUFSZ; config.buffer_count = 2; +#ifdef CONFIG_QSD_AUDIO_CALLREC + config.buffer_size = pcm->buffer_size; + config.sample_rate = pcm->sample_rate; + config.channel_count = pcm->channel_count; +#else + config.buffer_size = buffer_size; config.sample_rate = sample_rate; config.channel_count = channel_count; +#endif config.unused[0] = 0; config.unused[1] = 0; config.unused[2] = 0; @@ -109,6 +172,22 @@ static long q6_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int q6_in_open(struct inode *inode, struct file *file) { +#ifdef CONFIG_QSD_AUDIO_CALLREC + struct pcm *pcm; + + pr_info("pcm_in: open\n"); + pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL); + + if (!pcm) + return -ENOMEM; + + pcm->channel_count = 1; + pcm->sample_rate = 8000; + pcm->buffer_size = BUFSZ; + pcm->rec_mode = AUDIO_FLAG_READ; + file->private_data = pcm; + return 0; +#else int rc; pr_info("pcm_in: open\n"); @@ -122,19 +201,27 @@ static int q6_in_open(struct inode *inode, struct file *file) } mutex_unlock(&pcm_in_lock); return rc; +#endif } static ssize_t q6_in_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { +#ifdef CONFIG_QSD_AUDIO_CALLREC + struct pcm *pcm = file->private_data; +#endif struct audio_client *ac; struct audio_buffer *ab; const char __user *start = buf; int xfer; int res; +#ifndef CONFIG_QSD_AUDIO_CALLREC mutex_lock(&pcm_in_lock); ac = file->private_data; +#else + ac = pcm->ac; +#endif if (!ac) { res = -ENODEV; goto fail; @@ -169,19 +256,27 @@ static ssize_t q6_in_read(struct file *file, char __user *buf, } fail: res = buf - start; +#ifndef CONFIG_QSD_AUDIO_CALLREC mutex_unlock(&pcm_in_lock); - +#endif return res; } static int q6_in_release(struct inode *inode, struct file *file) { int rc = 0; +#ifdef CONFIG_QSD_AUDIO_CALLREC + struct pcm *pcm = file->private_data; + if (pcm->ac) + rc = q6audio_close(pcm->ac); + kfree(pcm); +#else mutex_lock(&pcm_in_lock); if (file->private_data) rc = q6audio_close(file->private_data); pcm_in_opened = 0; mutex_unlock(&pcm_in_lock); +#endif pr_info("pcm_in: release\n"); return rc; } diff --git a/arch/arm/mach-msm/qdsp6_1550/q6audio.c b/arch/arm/mach-msm/qdsp6_1550/q6audio.c index a972b97d..b187f77d 100644 --- a/arch/arm/mach-msm/qdsp6_1550/q6audio.c +++ b/arch/arm/mach-msm/qdsp6_1550/q6audio.c @@ -538,6 +538,9 @@ static int audio_out_open(struct audio_client *ac, uint32_t bufsz, } static int audio_in_open(struct audio_client *ac, uint32_t bufsz, +#ifdef CONFIG_QSD_AUDIO_CALLREC + uint32_t flags, +#endif uint32_t rate, uint32_t channels) { int r; @@ -552,7 +555,14 @@ static int audio_in_open(struct audio_client *ac, uint32_t bufsz, rpc.numdev = 1; rpc.dev[0] = ADSP_AUDIO_DEVICE_ID_DEFAULT; +#ifdef CONFIG_QSD_AUDIO_CALLREC + if (flags == AUDIO_FLAG_READ) + rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; + else + rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_MIXED_RECORD; +#else rpc.stream_context = ADSP_AUDIO_DEVICE_CONTEXT_RECORD; +#endif rpc.buf_max_size = bufsz; rpc.format = ADSP_AUDIO_FORMAT_PCM; @@ -1554,6 +1564,31 @@ static int audio_update_acdb(uint32_t adev, uint32_t acdb_id) return 0; } +#ifdef CONFIG_QSD_AUDIO_CALLREC +static void adie_rx_path_enable(uint32_t acdb_id) +{ + if (audio_rx_path_id) { + adie_enable(); + adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX); + adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); + + adie_proceed_to_stage(adie, ADIE_PATH_RX, + ADIE_STAGE_DIGITAL_READY); + adie_proceed_to_stage(adie, ADIE_PATH_RX, + ADIE_STAGE_DIGITAL_ANALOG_READY); + } +} + +static void q6_rx_path_enable(int reconf, uint32_t acdb_id) +{ + audio_update_acdb(audio_rx_device_id, acdb_id); + if (!reconf) + qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id); + qdsp6_standby(ac_control); + qdsp6_start(ac_control); +} +#endif + static void _audio_rx_path_enable(int reconf, uint32_t acdb_id) { AUDIO_INFO("%s\n", __func__); @@ -2182,20 +2217,36 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, if (audio_rx_path_refcount == 1) { _audio_rx_clk_enable(); +#ifdef CONFIG_QSD_AUDIO_CALLREC + q6_rx_path_enable(0, acdb_id); + adie_rx_path_enable(acdb_id); +#else // audio_update_acdb(audio_rx_device_id, acdb_id); qdsp6_devchg_notify(ac_control, ADSP_AUDIO_RX_DEVICE, audio_rx_device_id); qdsp6_standby(ac_control); qdsp6_start(ac_control); audio_update_acdb(audio_rx_device_id, acdb_id); +#endif } } else { /* TODO: consider concurrency with voice call */ - tx_clk_freq = rate; +#ifdef CONFIG_QSD_AUDIO_CALLREC + if (audio_tx_path_refcount > 0) { + tx_clk_freq = 8000; + } else { + tx_clk_freq = rate; + } +#else + tx_clk_freq = rate; +#endif audio_tx_path_refcount++; if (audio_tx_path_refcount == 1) { +#ifdef CONFIG_QSD_AUDIO_CALLREC + tx_clk_freq = rate; +#endif _audio_tx_clk_enable(); _audio_tx_path_enable(0, acdb_id); } @@ -2207,7 +2258,11 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, if (ac->flags & AUDIO_FLAG_WRITE) rc = audio_out_open(ac, bufsz, rate, channels); else - rc = audio_in_open(ac, bufsz, rate, channels); +#ifdef CONFIG_QSD_AUDIO_CALLREC + rc = audio_in_open(ac, bufsz, flags, rate, channels); +#else + rc = audio_in_open(ac, bufsz, rate, channels); +#endif if (rc == 0) break; if (retry == 0) @@ -2236,6 +2291,7 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, { if (audio_rx_path_refcount == 1) { +#ifndef CONFIG_QSD_AUDIO_CALLREC adie_enable(); adie_set_path(adie, audio_rx_path_id, ADIE_PATH_RX); adie_set_path_freq_plan(adie, ADIE_PATH_RX, 48000); @@ -2243,6 +2299,7 @@ struct audio_client *q6audio_open_pcm(uint32_t bufsz, uint32_t rate, adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_READY); adie_proceed_to_stage(adie, ADIE_PATH_RX, ADIE_STAGE_DIGITAL_ANALOG_READY); +#endif audio_rx_analog_enable(1); } }