static int pcm_write_wrapper(struct pcm *pcm, const void * buffer, size_t bytes, int flags) { int ret = 0; if(flags & PCM_MMAP) ret = pcm_mmap_write(pcm, (void *)buffer, bytes); else ret = pcm_write(pcm, (void *)buffer, bytes);一般都沒有用 MMAP.
所以都是直接 call pcm_write( )
tinyalsa 實做的 pcm_write( ) 就是用for loop 把 buffer 一一寫入 ioctl:
struct snd_xferi x; x.buf = (void*)data; x.frames = count / (pcm->config.channels * pcm_format_to_bits(pcm->config.format) / 8); ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))這樣就進入 kernel 了..
kernel 的 snd_pcm_playback_ioctl1 呼叫 snd_pcm_lib_write 來做:
static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, unsigned int hwoff, unsigned long data, unsigned int off, snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; int err; char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); if (substream->ops->copy) { if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) return err; } else { char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) return -EFAULT; } return 0; }
錯了。結果是用 MMAP...
所以,trace 到最後,是 call kernel 的 snd_pcm_sync_ptr..
修改一下 hardware/imx/alsa/tinyalsa_hal.c, 拿掉 MMAP, 就會 call pcm_write(), 就可以換掉 pcm_write 了..
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/alsa/tinyalsa_hal.c b/alsa/tinyalsa_hal.c | |
index a4644ac..2b85b88 100644 | |
--- a/alsa/tinyalsa_hal.c | |
+++ b/alsa/tinyalsa_hal.c | |
@@ -16,7 +16,7 @@ | |
/* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. */ | |
#define LOG_TAG "audio_hw_primary" | |
-//#define LOG_NDEBUG 0 | |
+#define LOG_NDEBUG 0 | |
#include <errno.h> | |
#include <pthread.h> | |
@@ -524,7 +524,7 @@ static int start_output_stream_primary(struct imx_stream_out *out) | |
pcm_device = out->device & (AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_AUX_DIGITAL); | |
if (pcm_device && (adev->active_output[OUTPUT_ESAI] == NULL || adev->active_output[OUTPUT_ESAI]->standby)) { | |
- out->write_flags[PCM_NORMAL] = PCM_OUT | PCM_MMAP | PCM_MONOTONIC; | |
+ out->write_flags[PCM_NORMAL] = PCM_OUT | PCM_MONOTONIC; | |
out->write_threshold[PCM_NORMAL] = PLAYBACK_LONG_PERIOD_COUNT * LONG_PERIOD_SIZE; | |
out->config[PCM_NORMAL] = pcm_config_mm_out; | |
@@ -1175,6 +1175,27 @@ static int pcm_read_wrapper(struct pcm *pcm, const void * buffer, size_t bytes) | |
return ret; | |
} | |
+static int s_pcm_write(struct pcm *pcm, void * buffer, size_t bytes) | |
+{ | |
+ int i; | |
+ unsigned short *dst; | |
+ unsigned short *src; | |
+ unsigned short patten = 0x0000; | |
+ int rc; | |
+ | |
+ dst = (unsigned short*)malloc(bytes); | |
+ src = (unsigned short*)buffer; | |
+ | |
+ for(i=0 ; i<bytes/2 ; i++) | |
+ dst[i]=src[i]; | |
+ | |
+ rc = pcm_write(pcm, (void*)dst, bytes); | |
+ free(dst); | |
+ return rc; | |
+ | |
+ | |
+} | |
static int pcm_write_wrapper(struct pcm *pcm, const void * buffer, size_t bytes, int flags) | |
{ | |
@@ -1182,7 +1203,7 @@ static int pcm_write_wrapper(struct pcm *pcm, const void * buffer, size_t bytes, | |
if(flags & PCM_MMAP) | |
ret = pcm_mmap_write(pcm, (void *)buffer, bytes); | |
else | |
- ret = pcm_write(pcm, (void *)buffer, bytes); | |
+ ret = s_pcm_write(pcm, (void *)buffer, bytes); | |
if(ret !=0) { | |
ALOGW("ret %d, pcm write %d error %s", ret, bytes, pcm_get_error(pcm)); | |
@@ -1200,7 +1221,7 @@ static int pcm_write_wrapper(struct pcm *pcm, const void * buffer, size_t bytes, | |
if(flags & PCM_MMAP) | |
ret = pcm_mmap_write(pcm, (void *)buffer, bytes); | |
else | |
- ret = pcm_write(pcm, (void *)buffer, bytes); | |
+ ret = s_pcm_write(pcm, (void *)buffer, bytes); | |
} | |
return ret; |
沒有留言:
張貼留言