android13/hardware/rockchip/audio/tinyalsa_hal/bitstream/audio_iec958.c

337 lines
10 KiB
C
Executable File

/*
* Copyright 2020 Rockchip Electronics Co. LTD
*
* 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.
*
* Author: hh@rock-chips.com
* Date: 2021/11/27
*/
#include <utils/Log.h>
#include "stdio.h"
#include <stdlib.h>
#include <string.h>
#include "audio_iec958.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "iec958"
/* see IEC 60958-3-2006.pdf
*
* Byte 2: Source and channel number
* Bits 16~19 Source number, bit 16 = LSB, bit 19 = MSB
* Bit 16, 17, 18, 19
* State 0 0 0 0 Do not take into account
* 1 0 0 0 1
* 0 1 0 0 2
* 1 1 0 0 3
* ......
* 1 1 1 1 15
*
* Bits 20 to 23 Channel number(audio channel), bit 20 = LSB, bit 23 = MSB
* Bit 20 21 22 23
* State 0 0 0 0 Do not take into account
* 1 0 0 0 (left channel for stereo channel format)
* 0 1 0 0 (right channel for stereo channel format)
* 1 1 0 0
* ......
* 1 1 1 1
*
*
* Byte 3 Sampling frequency and clock accuracy
* Bit 24~27 for samplerate
* Bit 24, 25, 26, 27
* State: 0 0 1 0 22050 hz
* 0 0 0 0 44100 hz
* 0 0 0 1 88200 hz
* 0 0 1 1 176400 hz
* 0 1 1 0 24000 hz
* 0 1 0 0 48000 hz
* 0 1 0 1 96000 hz
* 0 1 1 1 192000 hz
* 1 1 0 0 32000 hz
* 1 0 0 0 samplerate not indicated
* 1 0 0 1 768000 hz
*
*
* Bit 32 Word length
* Bit 0 Maximum audio sample word length is 20bis
* 1 Maximum audio sample word length is 24bis
*
*
* Bit 33~35 for sample word length
* Bit 33, 34, 35 Audio sample word length if
* maxumum lenth is 24bits(see bit32=1)
* indicated by bit 32
* State: 0 0 0 Word length not indicated dicated
* (default)
* 1 0 0 20bits
* 0 1 0 22bits
* 0 0 1 23bits
* 1 0 1 24bits
* 0 1 1 21bits
*
* Bit 33, 34, 35 Audio sample word length if
* maxumum lenth is 20bits(see bit32=0)
* indicated by bit 32
* State: 0 0 0 Word length not indicated dicated
* (default)
* 1 0 0 16bits
* 0 1 0 18bits
* 0 0 1 19bits
* 1 0 1 20bits
* 0 1 1 17bits
*
*
* Bit 36~39 for Original sampling frequency
* Bit 36 37 38 39
* State: 1 1 1 1 44100 hz
* 1 1 1 0 88200 hz
* 1 1 0 1 22050 hz
* 1 1 0 0 176400 hz
* 1 0 1 1 48000 hz
* 1 0 1 0 96000 hz
* 1 0 0 1 24000 hz
* 1 0 0 0 192000 hz
* 0 1 1 1 reserved
* 0 1 1 0 8000 hz
* 0 1 0 1 11025 hz
* 0 1 0 0 12000 hz
* 0 0 1 1 32000 hz
* 0 0 1 0 reserved
* 0 0 0 1 16000 hz
* 0 0 0 0 Original sampling frequency not indicated(default)
*/
unsigned int iec958_16to32(short *buffer) {
unsigned int data = (*buffer) << 16;
return data;
}
static unsigned int iec958_parity(unsigned int data) {
unsigned int parity;
int bit;
/*
* Compose 32bit IEC958 subframe, two sub frames
* build one frame with two channels.
*
* This is IP of HDMI data map:
* Audio Width 31 30 29 28 27 26 ...... 12 11 10 9 8 7 6 5 4 3 2 1 0
* 24 B P C U V MSB LSB
* 20 B P C U V MSB LSB
* 16 B P C U V MSB LSB
*
* So, for 16bit(IEC61937) to IEC958 subframe,
* bit 0-10 = padding
* 11-26 = data
* 27 = validity (0 for valid data, else 'in error')
* 28 = user data (0)
* 29 = channel status (24 bytes for 192 frames)
* 30 = parity
* 31 = block start
*/
parity = 0;
data >>= 11;
for (bit = 11; bit <= 29; bit++) {
if (data & 1)
parity++;
data >>= 1;
}
return (parity & 1);
}
static uint32_t iec958_subframe(rk_iec958 *iec, uint32_t data, int channel) {
unsigned int byte = iec->counter >> 3;
unsigned int mask = 1 << (iec->counter - (byte << 3));
data = (data & 0xffff0000) >> 5;
/* set IEC status bits (up to 192 bits) */
if (iec->status[byte] & mask)
data |= 0x20000000;
if (iec958_parity(data))
data |= 0x40000000;
/* block start */
if (!iec->counter)
data |= 0x80000000;
return data;
}
int iec958_frame_encode(rk_iec958 *iec, char *in, int inLength, char *out, int *outLength) {
if (iec == NULL)
return -1;
if (in == NULL || inLength <= 0 || out == NULL || outLength == NULL)
return -1;
int size = 2;
int counter = iec->counter;
int channels = iec->channels;
int frames = inLength/(size*channels);
int frame1 = frames;
short *input = NULL;
uint32_t *output = NULL;
uint32_t data = 0;
for (int channel = 0; channel < channels; ++channel) {
iec->counter = counter;
frame1 = frames;
input = (short *)in+channel;
output = (uint32_t *)out+channel;
while (frame1 > 0) {
data = iec958_16to32(input);
*output = iec958_subframe(iec, data, channel);
input += channels;
output += channels;
iec->counter++;
iec->counter %= 192;
frame1--;
}
}
*outLength = 2*inLength;
return 0;
}
void setResample(unsigned char *status, int sameplerate) {
// set AES3(Byte3) bit24~27
switch(sameplerate) {
case 22050:
*status = IEC958_AES3_CON_FS_22050;
break;
case 24000:
*status = IEC958_AES3_CON_FS_24000;
break;
case 32000:
*status = IEC958_AES3_CON_FS_32000;
break;
case 44100:
*status = IEC958_AES3_CON_FS_44100;
break;
case 48000:
*status = IEC958_AES3_CON_FS_48000;
break;
case 88200:
*status = IEC958_AES3_CON_FS_88200;
break;
case 96000:
*status = IEC958_AES3_CON_FS_96000;
break;
case 176400:
*status = IEC958_AES3_CON_FS_176400;
break;
case 192000:
*status = IEC958_AES3_CON_FS_192000;
break;
case 768000:
*status = IEC958_AES3_CON_FS_768000;
break;
default:
ALOGD("samplerate = %d not support", sameplerate);
break;
}
}
void setOriginalResample(unsigned char *status, int sameplerate) {
// set AES4(Byte4) bit36~39
switch(sameplerate) {
case 22050:
*status |= IEC958_AES4_CON_FS_22050;
break;
case 24000:
*status |= IEC958_AES4_CON_FS_24000;
break;
case 32000:
*status |= IEC958_AES4_CON_FS_32000;
break;
case 44100:
*status |= IEC958_AES4_CON_FS_44100;
break;
case 48000:
*status |= IEC958_AES4_CON_FS_48000;
break;
case 88200:
*status |= IEC958_AES4_CON_FS_88200;
break;
case 96000:
*status |= IEC958_AES4_CON_FS_96000;
break;
case 176400:
*status |= IEC958_AES4_CON_FS_176400;
break;
case 192000:
*status |= IEC958_AES4_CON_FS_192000;
break;
default:
break;
}
}
int iec958_init(rk_iec958 *iec, int samplerate, int channel, bool isPcm) {
const unsigned char pcm_status_bits[] = {
IEC958_AES0_CON_EMPHASIS_NONE, // Byte0 consumer, not-copyright, emphasis-none, mode=0
IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, // Byte1 original, PCM coder
0, // Byte2 source and channel
IEC958_AES3_CON_FS_48000, // Byte3 fs=48000Hz, clock accuracy=1000ppm
};
const unsigned char bistream_status_bits[] = {
IEC958_AES0_NONAUDIO, // non pcm
0, // bit8~bit15
0, // Byte2 source and channel bit16~bit23
IEC958_AES3_CON_FS_48000, // bit24~bit31
IEC958_AES4_CON_BITS24,
};
if (iec == NULL)
return -1;
iec->counter = 0;
memset(iec->status, 0, sizeof(iec->status));
if (isPcm) {
memcpy(iec->status, pcm_status_bits, sizeof(pcm_status_bits));
} else {
memcpy(iec->status, bistream_status_bits, sizeof(bistream_status_bits));
// HBR for example TRUEHD, DTS-HD using 768000 samplerate
if (channel == 8) {
samplerate = 768000;
}
}
// always using channel = 2 to convert IEC61937/PCM frame to IEC958 frame
channel = 2;
setResample(&iec->status[3], samplerate);
setOriginalResample(&iec->status[4], samplerate);
iec->samplerate = samplerate;
iec->channels = channel;
ALOGV("this = %p, status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x",
iec, iec->status[0], iec->status[1], iec->status[2], iec->status[3], iec->status[4]);
ALOGV("this = %p, samplerate = %d, channel = %d", iec, samplerate, channel);
return 0;
}
int iec958_deInit(rk_iec958 *iec) {
(void)iec;
return 0;
}