[RK3399]tc358743芯片的HDMI IN播放视频有电流声
一、前言
产品开发中发现HDMI IN输入音频的时候有电流声,分析得知hal层hdmiin的音频采样率和驱动指定采样率的不同。
二、代码路径
Android\kernel\drivers\media\i2c\tc35874x.c
Android\hardware\rockchip\audio\tinyalsa_hal\audio_hw.c
Android\kernel\drivers\media\v4l2-core\v4l2-dev.c
三、代码分析
audio_hw.c
static int get_hdmiin_audio_rate(struct audio_device *adev)
{
int rate = 44100;
char value[PROPERTY_VALUE_MAX] = "";
property_get("vendor.hdmiin.audiorate", value, STR_44_1KHZ);
if ( 0 == strncmp(value, STR_32KHZ, strlen(STR_32KHZ)) ){
rate = 32000;
}else if( 0 == strncmp(value, STR_44_1KHZ, strlen(STR_44_1KHZ)) ){
rate = 44100;
}else if( 0 == strncmp(value, STR_48KHZ, strlen(STR_48KHZ)) ){
rate = 48000;
} else {
rate = atoi(value);
if (rate <= 0)
rate = 44100;
}
// if hdmiin connect to codec, use 44100 sample rate
if (adev->dev_in[SND_IN_SOUND_CARD_HDMI].card
== adev->dev_out[SND_OUT_SOUND_CARD_SPEAKER].card)
rate = 44100;
ALOGD("%s rate =%d",__FUNCTION__,rate);//打印出来的rate是48000
return rate;
}
打印出来的rate是48000,并且挂示波器量的也是48000
tc35874x.c
static int get_audio_sampling_rate(struct v4l2_subdev *sd)
{
static const int code_to_rate[] = {
44100, 0, 48000, 32000, 22050, 384000, 24000, 352800,
88200, 768000, 96000, 705600, 176400, 0, 192000, 0
};
/* Register FS_SET is not cleared when the cable is disconnected */
if (no_signal(sd))
return 0;
//printk("i2c_rd8(sd, FS_SET) & MASK_FS = %d*******=%d\n",i2c_rd8(sd, FS_SET) & MASK_FS,code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]);
return code_to_rate[0];
}
可以看到返回的是44100,和48000明显不一致,这是导致电流声的主要原因。思路是做一个节点让hal层读出准确的值。
四、代码操作
tc35874x.c
#define FS_SET 0x8621
#define MASK_FS 0x0f
static int get_audio_sampling_rate(struct v4l2_subdev *sd)
{
static const int code_to_rate[] = {
44100, 0, 48000, 32000, 22050, 384000, 24000, 352800,
88200, 768000, 96000, 705600, 176400, 0, 192000, 0
};
/* Register FS_SET is not cleared when the cable is disconnected */
if (no_signal(sd))
return 0;
//printk("i2c_rd8(sd, FS_SET) & MASK_FS = %d*******=%d\n",i2c_rd8(sd, FS_SET) & MASK_FS,code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]);
+ return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS];
- return code_to_rate[0];
}
返回一个读寄存器的值,读出正确采样率的值,然后再添加如下, 将get_audio_sampling_rate读出来的值放入节点
+struct class *videodev_hdmirx_class(void);
+static ssize_t audio_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tc35874x_state *state = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d", get_audio_sampling_rate(&state->sd));
+}
+
+static ssize_t audio_present_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tc35874x_state *state = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d",
+ tx_5v_power_present(&state->sd) ? 1 : 0);
+}
+
+static DEVICE_ATTR_RO(audio_rate);
+static DEVICE_ATTR_RO(audio_present);
+static struct attribute *tc35874x_attrs[] = {
+ &dev_attr_audio_rate.attr,
+ &dev_attr_audio_present.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(tc35874x);
......
+struct class *videodev_hdmirx_class(void);//记得在v4l2-dev.c处理
......
static int tc35874x_probe...
...
+ state->classdev = device_create_with_groups(videodev_hdmirx_class(),
+ dev, MKDEV(0, 0),
+ state,
+ tc35874x_groups,
+ "tc35874x");
+ if (IS_ERR(state->classdev)) {
+ return -ENODEV;
+ }
v4l2-dev.c
+struct class *videodev_hdmirx_class(void)
+{
+ return &hdmirx_class;
+}
+EXPORT_SYMBOL(videodev_hdmirx_class);
然后在/sys/class/hdmirx/rk628/audio_rate节点中就可以读到相应的值,接下来是在hal层处理
audio_hw.c
#define MAX_BUFFER_SIZE 1024
+const char *ratePath = "/sys/class/hdmirx/rk628/audio_rate";
char buffer[MAX_BUFFER_SIZE];
.....
static int get_hdmiin_audio_rate(struct audio_device *adev)
{
int rate = 44100;
char value[PROPERTY_VALUE_MAX] = "";
property_get("vendor.hdmiin.audiorate", value, STR_44_1KHZ);
if ( 0 == strncmp(value, STR_32KHZ, strlen(STR_32KHZ)) ){
rate = 32000;
}else if( 0 == strncmp(value, STR_44_1KHZ, strlen(STR_44_1KHZ)) ){
rate = 44100;
}else if( 0 == strncmp(value, STR_48KHZ, strlen(STR_48KHZ)) ){
rate = 48000;
} else {
rate = atoi(value);
if (rate <= 0)
rate = 44100;
}
// if hdmiin connect to codec, use 44100 sample rate
if (adev->dev_in[SND_IN_SOUND_CARD_HDMI].card
== adev->dev_out[SND_OUT_SOUND_CARD_SPEAKER].card)
rate = 44100;
+ rate = readFromFile(ratePath);//强行将读取到的值返回
//ALOGD("%s rate =%d",__FUNCTION__,rate);//打开打印获取
return rate;
}
......
//readFromFile函数的实现
+int readFromFile(const char* filePath) {
+
+ char buffer[32] = {0};
+ FILE *file = fopen(filePath, "r");//打开路径节点
+ if (file == NULL) {
+ perror("Error opening file");
+ return -1;
+ }
+ int bytesRead = fread(buffer, 32, 1, file);//读出数据
+ //ALOGD("htc readFromFile = %s",buffer);//打印buffer
+ if (bytesRead < 0) {
+ perror("Error reading file");
+ fclose(file);//关闭
+ return -1;
+ }
+ //buffer[bytesRead] = '\0';
+ fclose(file);//关闭
+ return atoi(buffer);//转成整型
+}
这样就解决了HDMI音频电流声的问题,hal层和驱动层指定的采样率就一致了。
五、总结
audio_hw.c这个是非常重要的文件,可以多研究,很多音频的问题都在这里调整,还要音频策略的那个java文件进行调整