470 lines
13 KiB
C
Executable File
470 lines
13 KiB
C
Executable File
/*
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* @file audio_hw.h
|
|
* @brief
|
|
* ALSA Audio Git Log
|
|
* - V0.1.0:add alsa audio hal,just support 312x now.
|
|
* - V0.2.0:remove unused variable.
|
|
* - V0.3.0:turn off device when do_standby.
|
|
* - V0.4.0:turn off device before open pcm.
|
|
* - V0.4.1:Need to re-open the control to fix no sound when suspend.
|
|
* - V0.5.0:Merge the mixer operation from legacy_alsa.
|
|
* - V0.6.0:Merge speex denoise from legacy_alsa.
|
|
* - V0.7.0:add copyright.
|
|
* - V0.7.1:add support for box audio
|
|
* - V0.7.2:add support for dircet output
|
|
* - V0.8.0:update the direct output for box, add the DVI mode
|
|
* - V1.0.0:stable version
|
|
*
|
|
* @author RkAudio
|
|
* @version 1.0.8
|
|
* @date 2015-08-24
|
|
*/
|
|
|
|
#ifndef AUIDO_HW_H
|
|
#define AUIDO_HW_H
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
|
|
#include <cutils/log.h>
|
|
#include <cutils/properties.h>
|
|
#include <cutils/str_parms.h>
|
|
|
|
#include <hardware/audio.h>
|
|
#include <hardware/hardware.h>
|
|
|
|
#include <linux/videodev2.h>
|
|
|
|
#include <system/audio.h>
|
|
|
|
#include "asoundlib.h"
|
|
|
|
#include <audio_utils/resampler.h>
|
|
#include <audio_route/audio_route.h>
|
|
|
|
#include <poll.h>
|
|
#include <linux/fb.h>
|
|
#include <hardware_legacy/uevent.h>
|
|
|
|
#include "voice_preprocess.h"
|
|
#include "audio_hw_hdmi.h"
|
|
#include "denoise/rkdenoise.h"
|
|
#include "bitstream/audio_bitstream_manager.h"
|
|
#include <cutils/list.h>
|
|
|
|
#define AUDIO_HAL_VERSION "ALSA Audio Version: V1.1.0"
|
|
|
|
#define PCM_DEVICE 0
|
|
#define PCM_DEVICE_SCO 1
|
|
#define PCM_DEVICE_VOICE 2
|
|
#define PCM_DEVICE_HDMIIN 2
|
|
#define PCM_DEVICE_DEEP 3
|
|
/* for bt client call */
|
|
#define PCM_DEVICE_HFP 1
|
|
|
|
#define MIXER_CARD 0
|
|
|
|
/* duration in ms of volume ramp applied when starting capture to remove plop */
|
|
#define CAPTURE_START_RAMP_MS 100
|
|
|
|
/* default sampling for default output */
|
|
#define DEFAULT_PLAYBACK_SAMPLERATE 48000
|
|
|
|
#define DEFAULT_PLAYBACK_CHANNELS 2
|
|
|
|
/* default sampling for HDMI multichannel output */
|
|
#define HDMI_MULTI_DEFAULT_SAMPLING_RATE 48000
|
|
/* maximum number of channel mask configurations supported. Currently the primary
|
|
* output only supports 1 (stereo) and the multi channel HDMI output 2 (5.1 and 7.1) */
|
|
#define MAX_SUPPORTED_CHANNEL_MASKS 2
|
|
#define MAX_SUPPORTED_SAMPLE_RATES 2
|
|
|
|
#ifndef BOX_HAL
|
|
#define RK_DENOISE_ENABLE
|
|
#endif
|
|
|
|
#define HW_PARAMS_FLAG_LPCM 0
|
|
#define HW_PARAMS_FLAG_NLPCM 1
|
|
|
|
|
|
enum output_type {
|
|
OUTPUT_DEEP_BUF, // deep PCM buffers output stream
|
|
OUTPUT_LOW_LATENCY, // low latency output stream
|
|
OUTPUT_HDMI_MULTI, // HDMI multi channel
|
|
OUTPUT_DIRECT,
|
|
OUTPUT_TOTAL
|
|
};
|
|
|
|
struct direct_mode_t {
|
|
int output_mode;
|
|
char* hbr_Buf;
|
|
};
|
|
|
|
enum snd_out_sound_cards {
|
|
SND_OUT_SOUND_CARD_UNKNOWN = -1,
|
|
SND_OUT_SOUND_CARD_SPEAKER = 0,
|
|
SND_OUT_SOUND_CARD_HDMI,
|
|
SND_OUT_SOUND_CARD_HDMI_1,
|
|
SND_OUT_SOUND_CARD_SPDIF,
|
|
SND_OUT_SOUND_CARD_SPDIF_1,
|
|
SND_OUT_SOUND_CARD_BT,
|
|
SND_OUT_SOUND_CARD_MAX,
|
|
};
|
|
|
|
enum snd_in_sound_cards {
|
|
SND_IN_SOUND_CARD_UNKNOWN = -1,
|
|
SND_IN_SOUND_CARD_MIC = 0,
|
|
SND_IN_SOUND_CARD_BT,
|
|
SND_IN_SOUND_CARD_HDMI,
|
|
SND_IN_SOUND_CARD_MAX,
|
|
};
|
|
|
|
struct dev_proc_info
|
|
{
|
|
const char *cid; /* cardX/id match */
|
|
const char *did; /* dai id match */
|
|
};
|
|
|
|
struct dev_info
|
|
{
|
|
const char *id;
|
|
int card;
|
|
int device;
|
|
int score;
|
|
};
|
|
|
|
struct audio_device {
|
|
struct audio_hw_device hw_device;
|
|
|
|
pthread_mutex_t lock; /* see note below on mutex acquisition order */
|
|
audio_devices_t out_device; /* "or" of stream_out.device for all active output streams */
|
|
audio_devices_t in_device;
|
|
bool mic_mute;
|
|
struct audio_route *ar;
|
|
audio_source_t input_source;
|
|
audio_channel_mask_t in_channel_mask;
|
|
|
|
struct stream_out *outputs[OUTPUT_TOTAL];
|
|
pthread_mutex_t lock_outputs; /* see note below on mutex acquisition order */
|
|
unsigned int mode;
|
|
bool screenOff;
|
|
#ifdef AUDIO_3A
|
|
rk_process_api* voice_api;
|
|
#endif
|
|
|
|
/*
|
|
* hh@rock-chips.com
|
|
* this is for HDMI/SPDIF bitstream
|
|
* when HDMI/SPDIF bistream AC3/EAC3/DTS/TRUEHD/DTS-HD, some key tone or other pcm
|
|
* datas may come(play a Ac3 audio and seek the file to play). It is not allow to open sound card
|
|
* as pcm format and not allow to write pcm datas to HDMI/SPDIF sound cards when open it
|
|
* with config.flag = 1.
|
|
*/
|
|
int* owner[2];
|
|
|
|
struct dev_info dev_out[SND_OUT_SOUND_CARD_MAX];
|
|
struct dev_info dev_in[SND_IN_SOUND_CARD_MAX];
|
|
|
|
bool bt_wb_speech_enabled;
|
|
unsigned int bt_sco_reroute;
|
|
|
|
audio_patch_handle_t next_patch_handle; // Increase 1 when create audio patch
|
|
/* output */
|
|
struct listnode output_stream_list;
|
|
/* input */
|
|
struct listnode input_stream_list;
|
|
};
|
|
|
|
struct stream_out {
|
|
struct audio_stream_out stream;
|
|
|
|
pthread_mutex_t lock; /* see note below on mutex acquisition order */
|
|
struct pcm *pcm[SND_OUT_SOUND_CARD_MAX];
|
|
struct pcm_config config;
|
|
struct audio_config aud_config;
|
|
unsigned int pcm_device;
|
|
bool standby; /* true if all PCMs are inactive */
|
|
audio_devices_t device;
|
|
/* FIXME: when HDMI multichannel output is active, other outputs must be disabled as
|
|
* HDMI and WM1811 share the same I2S. This means that notifications and other sounds are
|
|
* silent when watching a 5.1 movie. */
|
|
bool disabled;
|
|
audio_channel_mask_t channel_mask;
|
|
/* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
|
|
audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
|
|
uint32_t supported_sample_rates[MAX_SUPPORTED_SAMPLE_RATES + 1];
|
|
bool muted;
|
|
uint64_t written; /* total frames written, not cleared when entering standby */
|
|
uint64_t nframes;
|
|
|
|
/*
|
|
* true: current stream take sound card in exclusive Mode, when this stream using this sound card,
|
|
* other stream can't using this sound card. This happen when current stream
|
|
* is multi pcm stream or bitstream. Multi channels pcm datas or bitstream datas can't be mixed.
|
|
* false: current stream is 2 channels pcm stream
|
|
*/
|
|
bool output_direct;
|
|
|
|
/*
|
|
* LPCM: pcm datas(include multi channels pcm)
|
|
* others: bitstream
|
|
*/
|
|
int output_direct_mode;
|
|
struct audio_device *dev;
|
|
struct resampler_itfe *resampler;
|
|
|
|
// for hdmi bitstream
|
|
rk_bistream *bistream;
|
|
|
|
struct hdmi_audio_infors hdmi_audio;
|
|
|
|
bool snd_reopen;
|
|
bool use_default_config;
|
|
float volume[2];
|
|
|
|
audio_io_handle_t handle; // Unique identifier for a stream
|
|
audio_patch_handle_t patch_handle; // Patch handle for this stream
|
|
struct listnode list_node;
|
|
audio_devices_t devices[AUDIO_PATCH_PORTS_MAX];
|
|
int num_configs;
|
|
};
|
|
|
|
struct stream_in {
|
|
struct audio_stream_in stream;
|
|
|
|
pthread_mutex_t lock; /* see note below on mutex acquisition order */
|
|
struct pcm *pcm;
|
|
bool standby;
|
|
|
|
unsigned int requested_rate;
|
|
struct resampler_itfe *resampler;
|
|
struct resampler_buffer_provider buf_provider;
|
|
int16_t *buffer;
|
|
size_t frames_in;
|
|
int read_status;
|
|
audio_source_t input_source;
|
|
audio_io_handle_t io_handle;
|
|
audio_devices_t device;
|
|
uint16_t ramp_vol;
|
|
uint16_t ramp_step;
|
|
size_t ramp_frames;
|
|
audio_channel_mask_t channel_mask;
|
|
audio_input_flags_t flags;
|
|
struct pcm_config *config;
|
|
|
|
struct audio_device *dev;
|
|
audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
|
|
uint32_t supported_sample_rates[MAX_SUPPORTED_SAMPLE_RATES + 1];
|
|
#ifdef RK_DENOISE_ENABLE
|
|
hrkdeniose mDenioseState;
|
|
#endif
|
|
uint32_t channel_flag;
|
|
int start_checkcount;
|
|
uint64_t frames_read;
|
|
|
|
audio_io_handle_t handle; // Unique identifier for a stream
|
|
audio_patch_handle_t patch_handle; // Patch handle for this stream
|
|
struct listnode list_node;
|
|
};
|
|
|
|
#define STRING_TO_ENUM(string) { #string, string }
|
|
|
|
struct string_to_enum {
|
|
const char *name;
|
|
uint32_t value;
|
|
};
|
|
|
|
static const struct string_to_enum channels_name_to_enum_table[] = {
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
|
|
STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
|
|
};
|
|
|
|
enum {
|
|
OUT_DEVICE_SPEAKER,
|
|
OUT_DEVICE_HEADSET,
|
|
OUT_DEVICE_HEADPHONES,
|
|
OUT_DEVICE_BT_SCO,
|
|
OUT_DEVICE_SPEAKER_AND_HEADSET,
|
|
OUT_DEVICE_OFF,
|
|
OUT_DEVICE_TAB_SIZE, /* number of rows in route_configs[][] */
|
|
OUT_DEVICE_NONE,
|
|
OUT_DEVICE_CNT
|
|
};
|
|
|
|
enum {
|
|
IN_SOURCE_MIC,
|
|
IN_SOURCE_CAMCORDER,
|
|
IN_SOURCE_VOICE_RECOGNITION,
|
|
IN_SOURCE_VOICE_COMMUNICATION,
|
|
IN_SOURCE_OFF,
|
|
IN_SOURCE_TAB_SIZE, /* number of lines in route_configs[][] */
|
|
IN_SOURCE_NONE,
|
|
IN_SOURCE_CNT
|
|
};
|
|
|
|
enum {
|
|
LPCM = 0,
|
|
NLPCM,
|
|
HBR,
|
|
};
|
|
|
|
struct route_config {
|
|
const char * const output_route;
|
|
const char * const input_route;
|
|
const char * const output_off;
|
|
const char * const input_off;
|
|
};
|
|
|
|
const struct route_config media_speaker = {
|
|
"media-speaker",
|
|
"media-main-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config media_headphones = {
|
|
"media-headphones",
|
|
"media-main-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config media_headset = {
|
|
"media-headphones",
|
|
"media-headset-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config camcorder_speaker = {
|
|
"media-speaker",
|
|
"media-second-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config camcorder_headphones = {
|
|
"media-headphones",
|
|
"media-second-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config voice_rec_speaker = {
|
|
"voice-rec-speaker",
|
|
"voice-rec-main-mic",
|
|
"incall-off",
|
|
"incall-off",
|
|
};
|
|
|
|
const struct route_config voice_rec_headphones = {
|
|
"voice-rec-headphones",
|
|
"voice-rec-main-mic",
|
|
"incall-off",
|
|
"incall-off",
|
|
};
|
|
|
|
const struct route_config voice_rec_headset = {
|
|
"voice-rec-headphones",
|
|
"voice-rec-headset-mic",
|
|
"incall-off",
|
|
"incall-off",
|
|
};
|
|
|
|
const struct route_config communication_speaker = {
|
|
"communication-speaker",
|
|
"communication-main-mic",
|
|
"voip-off",
|
|
"voip-off",
|
|
};
|
|
|
|
const struct route_config communication_headphones = {
|
|
"communication-headphones",
|
|
"communication-main-mic",
|
|
"voip-off",
|
|
"voip-off",
|
|
};
|
|
|
|
const struct route_config communication_headset = {
|
|
"communication-headphones",
|
|
"communication-headset-mic",
|
|
"voip-off",
|
|
"voip-off",
|
|
};
|
|
|
|
const struct route_config speaker_and_headphones = {
|
|
"speaker-and-headphones",
|
|
"main-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config bluetooth_sco = {
|
|
"bt-sco-headset",
|
|
"bt-sco-mic",
|
|
"playback-off",
|
|
"capture-off",
|
|
};
|
|
|
|
const struct route_config * const route_configs[IN_SOURCE_TAB_SIZE]
|
|
[OUT_DEVICE_TAB_SIZE] = {
|
|
{ /* IN_SOURCE_MIC */
|
|
&media_speaker, /* OUT_DEVICE_SPEAKER */
|
|
&media_headset, /* OUT_DEVICE_HEADSET */
|
|
&media_headphones, /* OUT_DEVICE_HEADPHONES */
|
|
&bluetooth_sco, /* OUT_DEVICE_BT_SCO */
|
|
&speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
|
|
},
|
|
{ /* IN_SOURCE_CAMCORDER */
|
|
&camcorder_speaker, /* OUT_DEVICE_SPEAKER */
|
|
&camcorder_headphones, /* OUT_DEVICE_HEADSET */
|
|
&camcorder_headphones, /* OUT_DEVICE_HEADPHONES */
|
|
&bluetooth_sco, /* OUT_DEVICE_BT_SCO */
|
|
&speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
|
|
},
|
|
{ /* IN_SOURCE_VOICE_RECOGNITION */
|
|
&voice_rec_speaker, /* OUT_DEVICE_SPEAKER */
|
|
&voice_rec_headset, /* OUT_DEVICE_HEADSET */
|
|
&voice_rec_headphones, /* OUT_DEVICE_HEADPHONES */
|
|
&bluetooth_sco, /* OUT_DEVICE_BT_SCO */
|
|
&speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
|
|
},
|
|
{ /* IN_SOURCE_VOICE_COMMUNICATION */
|
|
&communication_speaker, /* OUT_DEVICE_SPEAKER */
|
|
&communication_headset, /* OUT_DEVICE_HEADSET */
|
|
&communication_headphones, /* OUT_DEVICE_HEADPHONES */
|
|
&bluetooth_sco, /* OUT_DEVICE_BT_SCO */
|
|
&speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
|
|
}
|
|
};
|
|
|
|
static void do_out_standby(struct stream_out *out);
|
|
#endif
|
|
|