Skip to content

Commit

Permalink
Updated USB audio support
Browse files Browse the repository at this point in the history
Initial code for kernel-based rates detection
and failsafe operation.
  • Loading branch information
tsynik committed Jun 17, 2012
1 parent 315ee5b commit 37d5c6b
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 28 deletions.
1 change: 1 addition & 0 deletions libaudio/Android.mk
Expand Up @@ -23,6 +23,7 @@ LOCAL_C_INCLUDES += \
external/tinyalsa/include \
system/media/audio_utils/include \
system/media/audio_effects/include
LOCAL_CFLAGS += -fstack-protector -fstack-protector-all
LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libdl
LOCAL_MODULE_TAGS := optional

Expand Down
129 changes: 101 additions & 28 deletions libaudio/audio_hw.c 100755 → 100644
Expand Up @@ -14,13 +14,14 @@
* limitations under the License.
*/

#define LOG_TAG "A10_audio_HW"
#define LOG_TAG "sun4i_audio_hardware"
#define LOG_NDEBUG 0

#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <stdlib.h>

#include <cutils/log.h>
Expand Down Expand Up @@ -140,8 +141,6 @@ D/tinyalsa( 602): mix id:15 name:ADC Input Mux
/* ALSA cards for A10 */
#define CARD_A10_ABE 0
#define CARD_A10_HDMI 1
#define CARD_A10_USB 2
#define CARD_A10_FM 3
#define CARD_DEFAULT CARD_A10_ABE

/* ALSA ports for A10 */
Expand All @@ -156,25 +155,28 @@ D/tinyalsa( 602): mix id:15 name:ADC Input Mux
#define PORT_HDMI 0
#define PORT_USB 0

/* EXTERNAL DAC */
#define OUT_CARD_CID_PROPERTY "usb.audio.out.device"
#define OUT_CARD_CID "pcmC2D0p"
#define CAP_CARD_CID_PROPERTY "usb.audio.cap.device"
#define CAP_CARD_CID "pcmC2D0c"

/* constraint imposed by ABE: all period sizes must be multiples of 24 */
#define ABE_BASE_FRAME_COUNT 24
/* number of base blocks in a short period (low latency) */
//#define SHORT_PERIOD_MULTIPLIER 44 /* 22 ms */
#define SHORT_PERIOD_MULTIPLIER 80 /* 40 ms */
#define SHORT_PERIOD_MULTIPLIER 80 /* 40 ms */ //ex.44 /* 22 ms */
/* number of frames per short period (low latency) */
#define SHORT_PERIOD_SIZE (ABE_BASE_FRAME_COUNT * SHORT_PERIOD_MULTIPLIER)
/* number of short periods in a long period (low power) */
//#define LONG_PERIOD_MULTIPLIER 14 /* 308 ms */
#define LONG_PERIOD_MULTIPLIER 6 /* 240 ms */
#define LONG_PERIOD_MULTIPLIER 6 /* 240 ms */ //ex.14 /* 308 ms */
/* number of frames per long period (low power) */
#define LONG_PERIOD_SIZE (SHORT_PERIOD_SIZE * LONG_PERIOD_MULTIPLIER)
/* number of periods for low power playback */
#define PLAYBACK_LONG_PERIOD_COUNT 2
/* number of pseudo periods for low latency playback */
#define PLAYBACK_SHORT_PERIOD_COUNT 4
/* number of periods for capture */
// #define CAPTURE_PERIOD_COUNT 2
#define CAPTURE_PERIOD_COUNT 4
#define CAPTURE_PERIOD_COUNT 4 //ex.2
/* minimum sleep time in out_write() when write threshold is not reached */
#define MIN_WRITE_SLEEP_US 5000

Expand Down Expand Up @@ -260,10 +262,6 @@ D/tinyalsa( 602): mix id:15 name:ADC Input Mux
#define PRODUCT_NAME_PROPERTY "ro.product.name"
#define PRODUCT_DEVICE_TORO "toro"
#define PRODUCT_NAME_YAKJU "yakju"
#define AUDIO_OUT_DEV_PROPERTY "media.audio.out.mode"
#define AUDIO_OUT_CODEC "codec"
#define AUDIO_OUT_USB "usb"
#define AUDIO_OUT_FM "fm"

enum tty_modes {
TTY_MODE_OFF,
Expand Down Expand Up @@ -628,10 +626,26 @@ static int is_device_toro(void)
static int is_device_usb_dac(void)
{
char property[PROPERTY_VALUE_MAX];
property_get(AUDIO_OUT_DEV_PROPERTY, property, AUDIO_OUT_CODEC);
LOGV("### property: %s, value: %s", AUDIO_OUT_DEV_PROPERTY, property);
/* return true if the property matches the given value */
return strcmp(property, AUDIO_OUT_USB) == 0;
property_get(OUT_CARD_CID_PROPERTY, property, OUT_CARD_CID);
struct stat info;
char path[18]="/dev/snd/";
strcat(path, property);
int ret = stat(path, &info);
LOGV("# property: %s, value: %s, ret: %d", OUT_CARD_CID_PROPERTY, property, ret);
return(ret == -1 ? 0 : 1);
}

/* Returns true for external DAC, false otherwise */
static int is_device_usb_cap(void)
{
char property[PROPERTY_VALUE_MAX];
property_get(CAP_CARD_CID_PROPERTY, property, CAP_CARD_CID);
struct stat info;
char path[18]="/dev/snd/";
strcat(path, property);
int ret = stat(path, &info);
LOGV("# property: %s, value: %s, ret: %d", CAP_CARD_CID_PROPERTY, property, ret);
return(ret == -1 ? 0 : 1);
}

/* The enable flag when 0 makes the assumption that enums are disabled by
Expand Down Expand Up @@ -1159,7 +1173,7 @@ static void select_input_device(struct sun4i_audio_device *adev)
/* must be called with hw device and output stream mutexes locked */
static int start_output_stream(struct sun4i_stream_out *out)
{
F_LOG;
F_LOG;
struct sun4i_audio_device *adev = out->dev;
unsigned int card = CARD_DEFAULT;
unsigned int port = PORT_MM;
Expand All @@ -1175,21 +1189,47 @@ static int start_output_stream(struct sun4i_stream_out *out)
out->config.rate = MM_FULL_POWER_SAMPLING_RATE;
if (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
port = PORT_SPDIF;
LOGV("### SPDIF audio out selected! Sampling rate: %d Hz", MM_FULL_POWER_SAMPLING_RATE);
LOGV("### SPDIF audio out selected! Sampling rate: %d Hz", out->config.rate);
}
else if(adev->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
LOGV("### HDMI audio out selected! Sampling rate: %d Hz", MM_LOW_POWER_SAMPLING_RATE);
card = CARD_A10_HDMI;
port = PORT_HDMI;
out->config.rate = MM_LOW_POWER_SAMPLING_RATE;
LOGV("### HDMI audio out selected! Sampling rate: %d Hz", out->config.rate);
}
/* HACK: USB DAC output */
else if(is_device_usb_dac()) {
LOGV("### USB audio out selected! Sampling rate: %d Hz", MM_LOW_POWER_SAMPLING_RATE);
card = CARD_A10_USB;
port = PORT_USB;
char property[PROPERTY_VALUE_MAX];
property_get(OUT_CARD_CID_PROPERTY, property, OUT_CARD_CID);
// property value: pcmC[4]D[6]p
char *ptr;
ptr = property;
card = property[4] - '0';
port = property[6] - '0';
LOGV("# card: %u, port: %u, type: %s", card, port, &ptr[7]);
/* Define preferred rate */
out->config.rate = MM_LOW_POWER_SAMPLING_RATE;
/* HW Info (failsafe check) */
struct pcm_config config;
struct pcm *pcm;
pcm = pcm_hwinfo(card, port, PCM_OUT, &config);
if (!pcm || !pcm_is_ready(pcm)) {
LOGE("### Unable to get Hardware information for device %s (%s)\n",
property, pcm_get_error(pcm));
goto exit;
}
LOGV("# Supported Rates: (%uHz - %uHz)\n", config.rate_min, config.rate_max);
LOGV("# Supported Channels: (%uCh - %uCh)\n", config.channels_min, config.channels_max);
if (!(out->config.rate >= config.rate_min &&
out->config.rate <= config.rate_max)) {
LOGV("# Requested %dHz using supported value %dHz\n",out->config.rate, config.rate_max);
out->config.rate = config.rate_max;
}
pcm_close(pcm);
/* END of HW Info */
LOGV("### USB audio out selected! Sampling rate: %dHz", out->config.rate);
}
exit:
/* default to low power: will be corrected in out_write if necessary before first write to
* tinyalsa.
*/
Expand Down Expand Up @@ -1626,10 +1666,11 @@ static int out_remove_audio_effect(const struct audio_stream *stream, effect_han
/* must be called with hw device and input stream mutexes locked */
static int start_input_stream(struct sun4i_stream_in *in)
{
F_LOG;
F_LOG;
int ret = 0;
struct sun4i_audio_device *adev = in->dev;

unsigned int card = CARD_DEFAULT;
unsigned int port = PORT_MM2_UL;
adev->active_input = in;

if (adev->mode != AUDIO_MODE_IN_CALL) {
Expand All @@ -1643,9 +1684,41 @@ static int start_input_stream(struct sun4i_stream_in *in)
AUDIO_FORMAT_PCM_16_BIT,
in->config.channels,
in->requested_rate);
/* HACK: USB DAC input */
if(is_device_usb_cap()) {
char property[PROPERTY_VALUE_MAX];
property_get(CAP_CARD_CID_PROPERTY, property, CAP_CARD_CID);
// property value: pcmC[4]D[6]c
char *ptr = property;
card = property[4] - '0';
port = property[6] - '0';
LOGV("# card: %u, port: %u, type: %s", card, port, &ptr[7]);
/* Define preferred rate */
in->config.rate = MM_LOW_POWER_SAMPLING_RATE;
/* HW Info (failsafe check) */
struct pcm_config config;
struct pcm *pcm;
pcm = pcm_hwinfo(card, port, PCM_IN, &config);
if (!pcm || !pcm_is_ready(pcm)) {
LOGE("### Unable to get Hardware information for device %s (%s)\n",
property, pcm_get_error(pcm));
goto exit;
}
LOGV("# Supported Rates: (%uHz - %uHz)\n", config.rate_min, config.rate_max);
LOGV("# Supported Channels: (%uCh - %uCh)\n", config.channels_min, config.channels_max);
if (!(in->config.rate >= config.rate_min &&
in->config.rate <= config.rate_max)) {
LOGV("# Requested %dHz using supported value %dHz\n",in->config.rate, config.rate_max);
in->config.rate = config.rate_max;
}
pcm_close(pcm);
/* END of HW Info */
LOGV("### USB audio input selected! Sampling rate: %dHz", in->config.rate);
}
exit:

/* this assumes routing is done previously */
in->pcm = pcm_open(0, PORT_MM2_UL, PCM_IN, &in->config);
in->pcm = pcm_open(card, port, PCM_IN, &in->config);
if (!pcm_is_ready(in->pcm)) {
LOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
pcm_close(in->pcm);
Expand All @@ -1655,12 +1728,12 @@ static int start_input_stream(struct sun4i_stream_in *in)

/* if no supported sample rate is available, use the resampler */
if (in->resampler) {
F_LOG;
// F_LOG;
LOGV("### in->resampler");
in->resampler->reset(in->resampler);
in->frames_in = 0;
}
F_LOG;
// F_LOG;
return 0;
}

Expand Down

0 comments on commit 37d5c6b

Please sign in to comment.