blob: d184b17b30a51cd7c3bb4dd815064683e8035bf8 [file] [log] [blame]
/*
* Copyright (C) 2010 Amlogic Corporation.
*
* 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioSPDIF-wrap"
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sound/asound.h>
#include <cutils/log.h>
#include <system/audio.h>
#include "SPDIFEncoder.h"
#include <tinyalsa/asoundlib.h>
#include <cutils/properties.h>
#include <string.h>
#include "aml_dump_debug.h"
extern "C"
{
//#include "audio_hw_utils.h"
}
#define DD_FRAME_SIZE 1536
#define DDP_FRAME_SIZE 6144
// add array of dd/ddp mute frame for mute function
static const unsigned int muted_frame_dd[DD_FRAME_SIZE] = {
0x4e1ff872, 0x8000001, 0xb49e0b77, 0x43e10840, 0x10806f0, 0x21010808, 0x571f0104, 0xf9f33e7c, 0x9f3ee7cf, 0xfe757cfb, 0xf3e77cf9, 0x3e7ccf9f, 0x9d5ff8ff, 0xf9f33e7c, 0x9f3ee7cf, 0x24432ff,
0x8920, 0xb5f30001, 0x9b6de7cf, 0x6f1eb6db, 0x3c00, 0x9f3e0daf, 0x6db67cdb, 0xf1e1db78, 0x8000, 0xd7cf0006, 0x6db69f3e, 0xbc78db6d, 0xf000, 0x7cf936be, 0xb6dbf36d, 0xc7866de3,
0x0, 0x5f3e001b, 0xb6db7cf9, 0xf1e36db6, 0xc000, 0xf3e7daf9, 0xdb6dcdb6, 0x1e18b78f, 0x0, 0x7cf9006d, 0xdb6df3e6, 0xc78fb6db, 0x30000, 0xcf9f6be7, 0x6db636db, 0x7860de3c,
0x0, 0xf3e701b5, 0x6db6cf9b, 0x1e3cdb6f, 0xd0000, 0x3e7caf9f, 0xb6dbdb6d, 0xe18078f1, 0x0, 0xcf9f06d7, 0xb6db3e6d, 0x78f06dbc, 0x360000, 0xf9f3be7c, 0xdb6d6db6, 0x8000e3c7,
0x0, 0xe2560000
};
static const unsigned int muted_frame_ddp[DDP_FRAME_SIZE] = {
0x4e1ff872, 0x3000015, 0x7f01770b, 0x20e06734, 0x2004, 0x8084500, 0x404046c, 0x1010104, 0xe7630001, 0x7c3e9fcf, 0xcfe7f3f9, 0xf97c3e9f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0xce7f9fcf, 0x7c3e9faf,
0xcfe7f3f9, 0xf97c3e9f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0xf37f9fcf, 0x9fcfe7ab, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0x7c3e9fcf, 0xcfe7f3f9, 0xf97c3e9f, 0x53dee7f3, 0xf0e9,
0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0, 0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d,
0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000, 0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0, 0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0,
0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5, 0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db, 0x707777c7, 0x0, 0x0, 0x0, 0x0,
0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x2060, 0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0, 0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a,
0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d, 0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000, 0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0,
0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0, 0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5, 0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db,
0x707777c7, 0x0, 0x0, 0x0, 0x0, 0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x2060, 0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0,
0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d, 0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000,
0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0, 0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0, 0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5,
0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db, 0x707777c7, 0x0, 0x0, 0x0, 0x0, 0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x40, 0x7f227c55
};
static int mute_dd_frame(void *buf, size_t bytes)
{
if (bytes == (DD_FRAME_SIZE * 4))
memcpy(buf, muted_frame_dd, bytes);
else
memset(buf, 0, bytes);
return 0;
}
static int mute_ddp_frame(void *buf, size_t bytes)
{
if (bytes == (DDP_FRAME_SIZE * 4))
memcpy(buf, muted_frame_ddp, bytes);
else
memset(buf, 0, bytes);
return 0;
}
namespace android
{
class MySPDIFEncoder : public SPDIFEncoder
{
public:
MySPDIFEncoder(struct pcm *mypcm, audio_format_t format)
: SPDIFEncoder(format),
pcm_handle(mypcm), mTotalBytes(0),
mMute(false),// eac3_frame(0),
mFormat(format),
mFirstFrameMuted(false)
{};
virtual ssize_t writeOutput(const void* buffer, size_t bytes)
{
int ret = -1;
char *buf = (char *)buffer;
ALOGV("write size %zu \n", bytes);
if (get_debug_value(AML_DUMP_AUDIOHAL_SPDIF)) {
aml_dump_audio_bitstreams("hdmi_audio_out.spdif", buffer, bytes);
}
mTotalBytes += bytes;
if (mMute) {
muteFrame(buf, bytes);
}
if (mFirstFrameMuted == false) {
//memset(buf, 0, bytes);
mFirstFrameMuted = true;
}
/*to avoid ca noise in Sony TV*/
{
struct snd_pcm_status status;
pcm_ioctl(pcm_handle, SNDRV_PCM_IOCTL_STATUS, &status);
if (status.state == PCM_STATE_SETUP ||
status.state == PCM_STATE_PREPARED ||
status.state == PCM_STATE_XRUN) {
ALOGI("mute the first raw data");
memset(buf, 0, bytes);
}
}
ret = pcm_write(pcm_handle, buffer, bytes);
if (ret)
return ret;
return bytes;
}
virtual uint64_t total_bytes()
{
return mTotalBytes;
}
int setMute(bool mute)
{
ALOGD("%s(), mMute = %d \n", __func__, mute);
return mMute = mute;
}
bool getMute(void)
{
return mMute;
}
int muteFrame(void *buf, size_t bytes)
{
if (mFormat == AUDIO_FORMAT_E_AC3) {
mute_ddp_frame(buf, bytes);
} else if (mFormat == AUDIO_FORMAT_AC3) {
mute_dd_frame(buf, bytes);
} else {
// add new if needed
memset(buf, 0, bytes);
}
return 0;
}
protected:
struct pcm *pcm_handle;
private:
uint64_t mTotalBytes;
bool mMute;
// uint64_t eac3_frame;
audio_format_t mFormat;
bool mFirstFrameMuted;
};
static MySPDIFEncoder *myencoder = NULL;
extern "C" int spdifenc_init(struct pcm *mypcm, audio_format_t format)
{
if (myencoder) {
delete myencoder;
myencoder = NULL;
}
myencoder = new MySPDIFEncoder(mypcm, format);
if (myencoder == NULL) {
ALOGE("init SPDIFEncoder failed \n");
return -1;
}
ALOGI("init SPDIFEncoder done\n");
return 0;
}
extern "C" int spdifenc_write(const void *buffer, size_t numBytes)
{
return myencoder->write(buffer, numBytes);
}
extern "C" uint64_t spdifenc_get_total()
{
return myencoder->total_bytes();
}
extern "C" int spdifenc_set_mute(bool mute)
{
if (myencoder)
return myencoder->setMute(mute);
else
return -1;
}
}