summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com>2023-09-24 18:56:31 -0700
committerPindar Yang <pindaryang@google.com>2023-09-25 06:43:07 +0000
commitcf1ea7b7acb7db1ef24aafde7edaba9b751ea98f (patch)
tree1743b409668b3f9bd40ce76fd786e13b4e96479d
parent88d2aee3ebaee9f71daa00165df87ab165630e9d (diff)
parentc9dd2fed370952e9b995322dfb29a2f74f0e57f4 (diff)
downloadaoc-cf1ea7b7acb7db1ef24aafde7edaba9b751ea98f.tar.gz
Bug: 300854197 SBMerger: 558810260 Change-Id: Ia0c91cabf4df69e46de4f00dda6b062ec38a5e40 Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r--alsa/aoc_alsa.h8
-rw-r--r--alsa/aoc_alsa_incall.c32
-rw-r--r--alsa/aoc_alsa_pcm.c65
-rw-r--r--alsa/aoc_alsa_voip.c17
4 files changed, 90 insertions, 32 deletions
diff --git a/alsa/aoc_alsa.h b/alsa/aoc_alsa.h
index a9c30ab..9272bbb 100644
--- a/alsa/aoc_alsa.h
+++ b/alsa/aoc_alsa.h
@@ -196,7 +196,8 @@ enum aec_ref_source {
BT_PLAYBACK,
NUM_AEC_REF_SOURCE
};
-enum { INCALL_CAPTURE_OFF = 0, INCALL_CAPTURE_UL, INCALL_CAPTURE_DL, INCALL_CAPTURE_UL_DL };
+enum { INCALL_CAPTURE_OFF = 0, INCALL_CAPTURE_UL, INCALL_CAPTURE_DL, INCALL_CAPTURE_UL_DL,
+ INCALL_CAPTURE_3MIC };
enum { NONBLOCKING = 0, BLOCKING = 1 };
enum { STOP = 0, START };
enum { PLAYBACK_MODE, VOICE_TX_MODE, VOICE_RX_MODE, HAPTICS_MODE, OFFLOAD_MODE };
@@ -300,11 +301,15 @@ struct aoc_alsa_stream {
int params_rate; /* Sampling rate */
int pcm_format_width; /* Number of bits */
bool pcm_float_fmt; /* Floating point */
+ bool reused_for_voip;
struct vm_area_struct *vma; /* for MMAP */
unsigned int period_size;
unsigned int buffer_size;
unsigned int pos;
+ unsigned int prev_pos;
+ unsigned int pos_delta;
+ unsigned long prev_buffer_cnt;
unsigned long hw_ptr_base; /* read/write pointers in ring buffer */
unsigned long prev_consumed;
int n_overflow;
@@ -326,6 +331,7 @@ void aoc_timer_restart(struct aoc_alsa_stream *alsa_stream);
void aoc_timer_stop(struct aoc_alsa_stream *alsa_stream);
void aoc_timer_stop_sync(struct aoc_alsa_stream *alsa_stream);
void aoc_pcm_period_work_handler(struct work_struct *work);
+bool aoc_pcm_update_pos(struct aoc_alsa_stream *alsa_stream, unsigned long consumed);
int snd_aoc_new_ctl(struct aoc_chip *chip);
int snd_aoc_new_pcm(struct aoc_chip *chip);
diff --git a/alsa/aoc_alsa_incall.c b/alsa/aoc_alsa_incall.c
index 56a1ac7..29e1bbd 100644
--- a/alsa/aoc_alsa_incall.c
+++ b/alsa/aoc_alsa_incall.c
@@ -77,14 +77,10 @@ static enum hrtimer_restart aoc_incall_hifi_irq_process(struct aoc_alsa_stream *
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0
@@ -216,6 +212,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -242,6 +239,10 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
/* TODO: refactor needed on mapping between device number and entrypoint */
alsa_stream->entry_point_idx = (idx == 7) ? HAPTICS : idx;
+ if (rtd->dai_link->id == IDX_INCALL_CAP0_TX &&
+ chip->incall_capture_state[0] == INCALL_CAPTURE_3MIC) {
+ alsa_stream->reused_for_voip = true;
+ }
mutex_unlock(&chip->audio_mutex);
return 0;
@@ -322,6 +323,12 @@ static int snd_aoc_pcm_close(struct snd_soc_component *component,
*/
chip->opened &= ~(1 << alsa_stream->idx);
+ if (alsa_stream->reused_for_voip) {
+ /* Userspace should only select one EP for VoIP capture and one EP for
+ * VoIP playback.
+ */
+ teardown_voipcall(alsa_stream);
+ }
mutex_unlock(&chip->audio_mutex);
return 0;
@@ -409,11 +416,14 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_read(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
dev_dbg(component->dev, "pcm prepare: hw_ptr_base = %lu\n", alsa_stream->hw_ptr_base);
@@ -421,6 +431,12 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos,
runtime->frame_bits);
+ if (alsa_stream->reused_for_voip) {
+ /* Userspace should only select one EP for VoIP capture and one EP for
+ * VoIP playback.
+ */
+ prepare_voipcall(alsa_stream);
+ }
mutex_unlock(&chip->audio_mutex);
return 0;
}
diff --git a/alsa/aoc_alsa_pcm.c b/alsa/aoc_alsa_pcm.c
index 157d265..14fbf12 100644
--- a/alsa/aoc_alsa_pcm.c
+++ b/alsa/aoc_alsa_pcm.c
@@ -133,6 +133,39 @@ void aoc_timer_stop_sync(struct aoc_alsa_stream *alsa_stream)
}
}
+bool aoc_pcm_update_pos(struct aoc_alsa_stream *alsa_stream, unsigned long consumed)
+{
+ unsigned long buffer_cnt;
+
+ /* Update the pcm pointer */
+ if (unlikely(alsa_stream->n_overflow)) {
+ alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
+ alsa_stream->hw_ptr_base) %
+ alsa_stream->buffer_size;
+ buffer_cnt = (consumed + 0x100000000 * alsa_stream->n_overflow -
+ alsa_stream->hw_ptr_base) / alsa_stream->buffer_size;
+ } else {
+ alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
+ buffer_cnt = (consumed - alsa_stream->hw_ptr_base) / alsa_stream->buffer_size;
+ }
+
+ /* Update hw_ptr if the consumed data is equal to or bigger than one period */
+ if (buffer_cnt == alsa_stream->prev_buffer_cnt)
+ alsa_stream->pos_delta = alsa_stream->pos - alsa_stream->prev_pos;
+ else {
+ alsa_stream->pos_delta = (alsa_stream->pos + alsa_stream->buffer_size *
+ (buffer_cnt - alsa_stream->prev_buffer_cnt)) -
+ alsa_stream->prev_pos;
+ if ((buffer_cnt - alsa_stream->prev_buffer_cnt) != 1)
+ pr_warn("idx(%d): buffer_cnt %ld, prev_buffer_cnt %ld, pos_delta = %d\n",
+ alsa_stream->idx, buffer_cnt, alsa_stream->prev_buffer_cnt,
+ alsa_stream->pos_delta);
+ alsa_stream->prev_buffer_cnt = buffer_cnt;
+ }
+
+ return (alsa_stream->pos_delta >= alsa_stream->period_size) ? true : false;
+}
+
/* Hardware definition
* TODO: different pcm may have different hardware setup,
* considering deep buffer and compressed offload buffer
@@ -198,14 +231,10 @@ static enum hrtimer_restart aoc_pcm_irq_process(struct aoc_alsa_stream *alsa_str
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0 || alsa_stream->pcm_period_wq == NULL)
@@ -343,6 +372,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -558,24 +588,29 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_read(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
pr_debug("pcm prepare: hw_ptr_base = %lu\n", alsa_stream->hw_ptr_base);
pr_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size,
alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits);
- /* Advance the write ptr in the DRAM ring buffer for mmap-based playback */
- if (alsa_stream->stream_type == MMAPED &&
- alsa_stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- avail = aoc_ring_bytes_available_to_write(dev->service, AOC_DOWN);
- if (!aoc_service_advance_write_index(dev->service, AOC_DOWN, avail)) {
- dev_err(&(dev->dev), "ERR: in advancing pcm playback writer ptr\n");
- }
+ if (alsa_stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
+ alsa_stream->stream_type = MMAPED;
+ /* Advance the write ptr in the DRAM ring buffer for mmap-based playback */
+ avail = aoc_ring_bytes_available_to_write(dev->service, AOC_DOWN);
+ if (!aoc_service_advance_write_index(dev->service, AOC_DOWN, avail))
+ dev_err(&(dev->dev), "ERR: in advancing pcm playback writer ptr\n");
+ } else
+ alsa_stream->stream_type = NORMAL;
}
out:
diff --git a/alsa/aoc_alsa_voip.c b/alsa/aoc_alsa_voip.c
index f6200dd..f9f85ba 100644
--- a/alsa/aoc_alsa_voip.c
+++ b/alsa/aoc_alsa_voip.c
@@ -76,14 +76,10 @@ static enum hrtimer_restart aoc_voip_irq_process(struct aoc_alsa_stream *alsa_st
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0
@@ -212,6 +208,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -400,11 +397,15 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
+
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_written(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
pr_notice("Start voip call\n");
err = prepare_voipcall(alsa_stream);