diff options
-rw-r--r-- | audio/audio_hw.c | 351 | ||||
-rw-r--r-- | audio/audio_policy.conf | 7 |
2 files changed, 237 insertions, 121 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c index aea5677..7a24bcf 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -45,8 +45,10 @@ #define MIXER_DL2_RIGHT_EQUALIZER "DL2 Right Equalizer" #define MIXER_DL1_MEDIA_PLAYBACK_VOLUME "DL1 Media Playback Volume" #define MIXER_DL1_VOICE_PLAYBACK_VOLUME "DL1 Voice Playback Volume" +#define MIXER_DL1_TONES_PLAYBACK_VOLUME "DL1 Tones Playback Volume" #define MIXER_DL2_MEDIA_PLAYBACK_VOLUME "DL2 Media Playback Volume" #define MIXER_DL2_VOICE_PLAYBACK_VOLUME "DL2 Voice Playback Volume" +#define MIXER_DL2_TONES_PLAYBACK_VOLUME "DL2 Tones Playback Volume" #define MIXER_SDT_DL_VOLUME "SDT DL Volume" #define MIXER_SDT_UL_VOLUME "SDT UL Volume" @@ -58,8 +60,10 @@ #define MIXER_DL1_EQUALIZER "DL1 Equalizer" #define MIXER_DL1_MIXER_MULTIMEDIA "DL1 Mixer Multimedia" #define MIXER_DL1_MIXER_VOICE "DL1 Mixer Voice" +#define MIXER_DL1_MIXER_TONES "DL1 Mixer Tones" #define MIXER_DL2_MIXER_MULTIMEDIA "DL2 Mixer Multimedia" #define MIXER_DL2_MIXER_VOICE "DL2 Mixer Voice" +#define MIXER_DL2_MIXER_TONES "DL2 Mixer Tones" #define MIXER_SIDETONE_MIXER_PLAYBACK "Sidetone Mixer Playback" #define MIXER_SIDETONE_MIXER_CAPTURE "Sidetone Mixer Capture" #define MIXER_DL2_MONO_MIXER "DL2 Mono Mixer" @@ -185,9 +189,6 @@ /* minimum sleep time in out_write() when write threshold is not reached */ #define MIN_WRITE_SLEEP_US 5000 -#define RESAMPLER_BUFFER_FRAMES (SHORT_PERIOD_SIZE * 2) -#define RESAMPLER_BUFFER_SIZE (4 * RESAMPLER_BUFFER_FRAMES) - #define DEFAULT_OUT_SAMPLING_RATE 44100 // 48000 is possible but interacts poorly with HDMI /* sampling rate when using MM low power port */ @@ -275,17 +276,22 @@ enum tty_modes { struct pcm_config pcm_config_mm = { .channels = 2, .rate = MM_FULL_POWER_SAMPLING_RATE, -#ifdef PLAYBACK_MMAP .period_size = LONG_PERIOD_SIZE, .period_count = PLAYBACK_LONG_PERIOD_COUNT, -#else + .format = PCM_FORMAT_S16_LE, + .start_threshold = LONG_PERIOD_SIZE, + .avail_min = LONG_PERIOD_SIZE, +}; + +struct pcm_config pcm_config_tones = { + .channels = 2, + .rate = MM_FULL_POWER_SAMPLING_RATE, .period_size = SHORT_PERIOD_SIZE, .period_count = PLAYBACK_SHORT_PERIOD_COUNT, -#endif .format = PCM_FORMAT_S16_LE, #ifdef PLAYBACK_MMAP - .start_threshold = SHORT_PERIOD_SIZE * 2, - .avail_min = LONG_PERIOD_SIZE, + .start_threshold = SHORT_PERIOD_SIZE, + .avail_min = SHORT_PERIOD_SIZE, #else .start_threshold = 0, .avail_min = 0, @@ -345,6 +351,14 @@ struct route_setting defaults[] = { .intval = MIXER_ABE_GAIN_0DB, }, { + .ctl_name = MIXER_DL1_TONES_PLAYBACK_VOLUME, + .intval = MIXER_ABE_GAIN_0DB, + }, + { + .ctl_name = MIXER_DL2_TONES_PLAYBACK_VOLUME, + .intval = MIXER_ABE_GAIN_0DB, + }, + { .ctl_name = MIXER_SDT_DL_VOLUME, .intval = MIXER_ABE_GAIN_0DB, }, @@ -556,6 +570,8 @@ struct mixer_ctls struct mixer_ctl *mm_dl2; struct mixer_ctl *vx_dl1; struct mixer_ctl *vx_dl2; + struct mixer_ctl *tones_dl1; + struct mixer_ctl *tones_dl2; struct mixer_ctl *earpiece_enable; struct mixer_ctl *dl2_mono; struct mixer_ctl *dl1_headset; @@ -570,6 +586,13 @@ struct mixer_ctls struct mixer_ctl *earpiece_volume; }; +enum output_type { + OUTPUT_DEEP_BUF, // deep PCM buffers output stream + OUTPUT_LOW_LATENCY, // low latency output stream + OUTPUT_TOTAL +}; + + struct tuna_audio_device { struct audio_hw_device hw_device; @@ -583,14 +606,13 @@ struct tuna_audio_device { int in_call; float voice_volume; struct tuna_stream_in *active_input; - struct tuna_stream_out *active_output; + struct tuna_stream_out *outputs[OUTPUT_TOTAL]; bool mic_mute; int tty_mode; struct echo_reference_itfe *echo_reference; bool bluetooth_nrec; bool device_is_toro; int wb_amr; - bool low_power; /* RIL */ struct ril_handle ril; @@ -611,11 +633,10 @@ struct tuna_stream_out { struct pcm *pcm[PCM_TOTAL]; struct resampler_itfe *resampler; char *buffer; + size_t buffer_frames; int standby; struct echo_reference_itfe *echo_reference; struct tuna_audio_device *dev; - int write_threshold; - bool low_power; }; #define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */ @@ -975,8 +996,11 @@ static void force_all_standby(struct tuna_audio_device *adev) struct tuna_stream_in *in; struct tuna_stream_out *out; - if (adev->active_output) { - out = adev->active_output; + /* only needed for low latency output streams as other streams are not used + * for voice use cases */ + if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL && + !adev->outputs[OUTPUT_LOW_LATENCY]->standby) { + out = adev->outputs[OUTPUT_LOW_LATENCY]; pthread_mutex_lock(&out->lock); do_output_standby(out); pthread_mutex_unlock(&out->lock); @@ -1091,9 +1115,11 @@ static void select_output_device(struct tuna_audio_device *adev) /* Select front end */ mixer_ctl_set_value(adev->mixer_ctls.mm_dl2, 0, speaker_on); + mixer_ctl_set_value(adev->mixer_ctls.tones_dl2, 0, speaker_on); mixer_ctl_set_value(adev->mixer_ctls.vx_dl2, 0, speaker_on && (adev->mode == AUDIO_MODE_IN_CALL)); mixer_ctl_set_value(adev->mixer_ctls.mm_dl1, 0, dl1_on); + mixer_ctl_set_value(adev->mixer_ctls.tones_dl1, 0, dl1_on); mixer_ctl_set_value(adev->mixer_ctls.vx_dl1, 0, dl1_on && (adev->mode == AUDIO_MODE_IN_CALL)); /* Select back end */ @@ -1238,7 +1264,7 @@ static void select_input_device(struct tuna_audio_device *adev) } /* must be called with hw device and output stream mutexes locked */ -static int start_output_stream(struct tuna_stream_out *out) +static int start_output_stream_low_latency(struct tuna_stream_out *out) { struct tuna_audio_device *adev = out->dev; #ifdef PLAYBACK_MMAP @@ -1249,39 +1275,37 @@ static int start_output_stream(struct tuna_stream_out *out) int i; bool success = true; - adev->active_output = out; - if (adev->mode != AUDIO_MODE_IN_CALL) { - /* FIXME: only works if only one output can be active at a time */ select_output_device(adev); } /* default to low power: will be corrected in out_write if necessary before first write to * tinyalsa. */ - out->write_threshold = PLAYBACK_LONG_PERIOD_COUNT * LONG_PERIOD_SIZE; - out->low_power = 1; if (adev->devices & (AUDIO_DEVICE_OUT_ALL & ~(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | AUDIO_DEVICE_OUT_AUX_DIGITAL))) { /* Something not a dock in use */ - out->config[PCM_NORMAL] = pcm_config_mm; + out->config[PCM_NORMAL] = pcm_config_tones; out->config[PCM_NORMAL].rate = MM_FULL_POWER_SAMPLING_RATE; - out->pcm[PCM_NORMAL] = pcm_open(CARD_TUNA_DEFAULT, PORT_MM, flags, &out->config[PCM_NORMAL]); + out->pcm[PCM_NORMAL] = pcm_open(CARD_TUNA_DEFAULT, PORT_TONES, + flags, &out->config[PCM_NORMAL]); } if (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) { /* SPDIF output in use */ - out->config[PCM_SPDIF] = pcm_config_mm; + out->config[PCM_SPDIF] = pcm_config_tones; out->config[PCM_SPDIF].rate = MM_FULL_POWER_SAMPLING_RATE; - out->pcm[PCM_SPDIF] = pcm_open(CARD_TUNA_DEFAULT, PORT_SPDIF, flags, &out->config[PCM_SPDIF]); + out->pcm[PCM_SPDIF] = pcm_open(CARD_TUNA_DEFAULT, PORT_SPDIF, + flags, &out->config[PCM_SPDIF]); } if(adev->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) { /* HDMI output in use */ - out->config[PCM_HDMI] = pcm_config_mm; + out->config[PCM_HDMI] = pcm_config_tones; out->config[PCM_HDMI].rate = MM_LOW_POWER_SAMPLING_RATE; - out->pcm[PCM_HDMI] = pcm_open(CARD_OMAP4_HDMI, PORT_HDMI, flags, &out->config[PCM_HDMI]); + out->pcm[PCM_HDMI] = pcm_open(CARD_OMAP4_HDMI, PORT_HDMI, + flags, &out->config[PCM_HDMI]); } /* Close any PCMs that could not be opened properly and return an error */ @@ -1295,6 +1319,10 @@ static int start_output_stream(struct tuna_stream_out *out) } if (success) { + out->buffer_frames = pcm_config_tones.period_size * 2; + if (out->buffer == NULL) + out->buffer = malloc(out->buffer_frames * audio_stream_frame_size(&out->stream.common)); + if (adev->echo_reference != NULL) out->echo_reference = adev->echo_reference; out->resampler->reset(out->resampler); @@ -1302,10 +1330,35 @@ static int start_output_stream(struct tuna_stream_out *out) return 0; } - adev->active_output = NULL; return -ENOMEM; } +/* must be called with hw device and output stream mutexes locked */ +static int start_output_stream_deep_buffer(struct tuna_stream_out *out) +{ + struct tuna_audio_device *adev = out->dev; + + if (adev->mode != AUDIO_MODE_IN_CALL) { + select_output_device(adev); + } + + out->config[PCM_NORMAL] = pcm_config_mm; + out->config[PCM_NORMAL].rate = MM_FULL_POWER_SAMPLING_RATE; + out->pcm[PCM_NORMAL] = pcm_open(CARD_TUNA_DEFAULT, PORT_MM, + PCM_OUT | PCM_MMAP | PCM_NOIRQ, &out->config[PCM_NORMAL]); + if (out->pcm[PCM_NORMAL] && !pcm_is_ready(out->pcm[PCM_NORMAL])) { + ALOGE("cannot open pcm_out driver: %s", pcm_get_error(out->pcm[PCM_NORMAL])); + pcm_close(out->pcm[PCM_NORMAL]); + out->pcm[PCM_NORMAL] = NULL; + return -ENOMEM; + } + out->buffer_frames = pcm_config_mm.period_size * 2; + if (out->buffer == NULL) + out->buffer = malloc(out->buffer_frames * audio_stream_frame_size(&out->stream.common)); + + return 0; +} + static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count) { if (format != AUDIO_FORMAT_PCM_16_BIT) @@ -1373,8 +1426,11 @@ static void put_echo_reference(struct tuna_audio_device *adev, { if (adev->echo_reference != NULL && reference == adev->echo_reference) { - if (adev->active_output != NULL) - remove_echo_reference(adev->active_output, reference); + /* echo reference is taken from the low latency output stream used + * for voice use cases */ + if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL && + !adev->outputs[OUTPUT_LOW_LATENCY]->standby) + remove_echo_reference(adev->outputs[OUTPUT_LOW_LATENCY], reference); release_echo_reference(reference); adev->echo_reference = NULL; } @@ -1386,8 +1442,12 @@ static struct echo_reference_itfe *get_echo_reference(struct tuna_audio_device * uint32_t sampling_rate) { put_echo_reference(adev, adev->echo_reference); - if (adev->active_output != NULL) { - struct audio_stream *stream = &adev->active_output->stream.common; + /* echo reference is taken from the low latency output stream used + * for voice use cases */ + if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL && + !adev->outputs[OUTPUT_LOW_LATENCY]->standby) { + struct audio_stream *stream = + &adev->outputs[OUTPUT_LOW_LATENCY]->stream.common; uint32_t wr_channel_count = popcount(stream->get_channels(stream)); uint32_t wr_sampling_rate = stream->get_sample_rate(stream); @@ -1399,7 +1459,8 @@ static struct echo_reference_itfe *get_echo_reference(struct tuna_audio_device * wr_sampling_rate, &adev->echo_reference); if (status == 0) - add_echo_reference(adev->active_output, adev->echo_reference); + add_echo_reference(adev->outputs[OUTPUT_LOW_LATENCY], + adev->echo_reference); } return adev->echo_reference; } @@ -1447,7 +1508,20 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) return 0; } -static size_t out_get_buffer_size(const struct audio_stream *stream) +static size_t out_get_buffer_size_low_latency(const struct audio_stream *stream) +{ + struct tuna_stream_out *out = (struct tuna_stream_out *)stream; + + /* take resampling into account and return the closest majoring + multiple of 16 frames, as audioflinger expects audio buffers to + be a multiple of 16 frames. Note: we use the default rate here + from pcm_config_tones.rate. */ + size_t size = (SHORT_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / pcm_config_tones.rate; + size = ((size + 15) / 16) * 16; + return size * audio_stream_frame_size((struct audio_stream *)stream); +} + +static size_t out_get_buffer_size_deep_buffer(const struct audio_stream *stream) { struct tuna_stream_out *out = (struct tuna_stream_out *)stream; @@ -1455,7 +1529,7 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) multiple of 16 frames, as audioflinger expects audio buffers to be a multiple of 16 frames. Note: we use the default rate here from pcm_config_mm.rate. */ - size_t size = (SHORT_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / pcm_config_mm.rate; + size_t size = (LONG_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / pcm_config_mm.rate; size = ((size + 15) / 16) * 16; return size * audio_stream_frame_size((struct audio_stream *)stream); } @@ -1480,8 +1554,11 @@ static int do_output_standby(struct tuna_stream_out *out) { struct tuna_audio_device *adev = out->dev; int i; + bool all_outputs_in_standby = true; if (!out->standby) { + out->standby = 1; + for (i = 0; i < PCM_TOTAL; i++) { if (out->pcm[i]) { pcm_close(out->pcm[i]); @@ -1489,12 +1566,15 @@ static int do_output_standby(struct tuna_stream_out *out) } } - adev->active_output = 0; - + for (i = 0; i < OUTPUT_TOTAL; i++) { + if (adev->outputs[i] != NULL && !adev->outputs[i]->standby) { + all_outputs_in_standby = false; + break; + } + } /* if in call, don't turn off the output stage. This will be done when the call is ended */ - if (adev->mode != AUDIO_MODE_IN_CALL) { - /* FIXME: only works if only one output can be active at a time */ + if (all_outputs_in_standby && adev->mode != AUDIO_MODE_IN_CALL) { set_route_by_array(adev->mixer, hs_output, 0); set_route_by_array(adev->mixer, hf_output, 0); } @@ -1504,8 +1584,6 @@ static int do_output_standby(struct tuna_stream_out *out) out->echo_reference->write(out->echo_reference, NULL); out->echo_reference = NULL; } - - out->standby = 1; } return 0; } @@ -1547,7 +1625,10 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); if (((adev->devices & AUDIO_DEVICE_OUT_ALL) != val) && (val != 0)) { - if (out == adev->active_output) { + /* this is needed only when changing device on low latency output + * as other output streams are not used for voice use cases nor + * handle duplication to HDMI or SPDIF */ + if (out == adev->outputs[OUTPUT_LOW_LATENCY] && !out->standby) { /* a change in output device may change the microphone selection */ if (adev->active_input && adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) { @@ -1599,12 +1680,20 @@ static char * out_get_parameters(const struct audio_stream *stream, const char * return strdup(""); } -static uint32_t out_get_latency(const struct audio_stream_out *stream) +static uint32_t out_get_latency_low_latency(const struct audio_stream_out *stream) { struct tuna_stream_out *out = (struct tuna_stream_out *)stream; /* Note: we use the default rate here from pcm_config_mm.rate */ - return (SHORT_PERIOD_SIZE * PLAYBACK_SHORT_PERIOD_COUNT * 1000) / pcm_config_mm.rate; + return (SHORT_PERIOD_SIZE * PLAYBACK_SHORT_PERIOD_COUNT * 1000) / pcm_config_tones.rate; +} + +static uint32_t out_get_latency_deep_buffer(const struct audio_stream_out *stream) +{ + struct tuna_stream_out *out = (struct tuna_stream_out *)stream; + + /* Note: we use the default rate here from pcm_config_mm.rate */ + return (LONG_PERIOD_SIZE * PLAYBACK_LONG_PERIOD_COUNT * 1000) / pcm_config_mm.rate; } static int out_set_volume(struct audio_stream_out *stream, float left, @@ -1613,7 +1702,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left, return -ENOSYS; } -static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, +static ssize_t out_write_low_latency(struct audio_stream_out *stream, const void* buffer, size_t bytes) { int ret; @@ -1621,16 +1710,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, struct tuna_audio_device *adev = out->dev; size_t frame_size = audio_stream_frame_size(&out->stream.common); size_t in_frames = bytes / frame_size; - size_t out_frames = RESAMPLER_BUFFER_SIZE / frame_size; + size_t out_frames = in_frames; bool force_input_standby = false; struct tuna_stream_in *in; - bool low_power; - int kernel_frames; - /* If we're in out_write, we will find at least one pcm active */ - int primary_pcm = -1; int i; - bool use_resampler = false; - int period_size = 0; /* acquiring hw device mutex systematically is useful if a low priority thread is waiting * on the output stream mutex - e.g. executing select_mode() while holding the hw device @@ -1639,7 +1722,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); if (out->standby) { - ret = start_output_stream(out); + ret = start_output_stream_low_latency(out); if (ret != 0) { pthread_mutex_unlock(&adev->lock); goto exit; @@ -1650,47 +1733,21 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) force_input_standby = true; } - low_power = adev->low_power && !adev->active_input; pthread_mutex_unlock(&adev->lock); -#ifdef PLAYBACK_MMAP - if (low_power != out->low_power) { - if (low_power) { - out->write_threshold = LONG_PERIOD_SIZE * PLAYBACK_LONG_PERIOD_COUNT; - period_size = LONG_PERIOD_SIZE; - } else { - out->write_threshold = SHORT_PERIOD_SIZE * PLAYBACK_SHORT_PERIOD_COUNT; - period_size = SHORT_PERIOD_SIZE; - - } - out->low_power = low_power; - } -#endif - for (i = 0; i < PCM_TOTAL; i++) { - if (out->pcm[i]) { - /* Make the first active PCM act as primary */ - if (primary_pcm < 0) - primary_pcm = i; - - if (period_size) - pcm_set_avail_min(out->pcm[i], period_size); - - if (out->config[i].rate != DEFAULT_OUT_SAMPLING_RATE) - use_resampler = true; + /* only use resampler if required */ + if (out->pcm[i] && (out->config[i].rate != DEFAULT_OUT_SAMPLING_RATE)) { + out_frames = out->buffer_frames; + out->resampler->resample_from_input(out->resampler, + (int16_t *)buffer, + &in_frames, + (int16_t *)out->buffer, + &out_frames); + break; } } - /* only use resampler if required */ - if (use_resampler) - out->resampler->resample_from_input(out->resampler, - (int16_t *)buffer, - &in_frames, - (int16_t *)out->buffer, - &out_frames); - else - out_frames = in_frames; - if (out->echo_reference != NULL) { struct echo_reference_buffer b; b.raw = (void *)buffer; @@ -1700,26 +1757,6 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, out->echo_reference->write(out->echo_reference, &b); } -#ifdef PLAYBACK_MMAP - /* do not allow more than out->write_threshold frames in kernel pcm driver buffer */ - do { - struct timespec time_stamp; - - if (pcm_get_htimestamp(out->pcm[primary_pcm], (unsigned int *)&kernel_frames, &time_stamp) < 0) - break; - kernel_frames = pcm_get_buffer_size(out->pcm[primary_pcm]) - kernel_frames; - - if (kernel_frames > out->write_threshold) { - unsigned long time = (unsigned long) - (((int64_t)(kernel_frames - out->write_threshold) * 1000000) / - MM_FULL_POWER_SAMPLING_RATE); - if (time < MIN_WRITE_SLEEP_US) - time = MIN_WRITE_SLEEP_US; - usleep(time); - } - } while (kernel_frames > out->write_threshold); -#endif - /* Write to all active PCMs */ for (i = 0; i < PCM_TOTAL; i++) { if (out->pcm[i]) { @@ -1757,6 +1794,55 @@ exit: return bytes; } +static ssize_t out_write_deep_buffer(struct audio_stream_out *stream, const void* buffer, + size_t bytes) +{ + int ret; + struct tuna_stream_out *out = (struct tuna_stream_out *)stream; + struct tuna_audio_device *adev = out->dev; + size_t frame_size = audio_stream_frame_size(&out->stream.common); + size_t in_frames = bytes / frame_size; + + /* acquiring hw device mutex systematically is useful if a low priority thread is waiting + * on the output stream mutex - e.g. executing select_mode() while holding the hw device + * mutex + */ + pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&out->lock); + if (out->standby) { + ret = start_output_stream_deep_buffer(out); + if (ret != 0) { + pthread_mutex_unlock(&adev->lock); + goto exit; + } + out->standby = 0; + } + pthread_mutex_unlock(&adev->lock); + + /* only use resampler if required */ + if (out->config[PCM_NORMAL].rate != DEFAULT_OUT_SAMPLING_RATE) { + size_t out_frames = out->buffer_frames; + + out->resampler->resample_from_input(out->resampler, + (int16_t *)buffer, + &in_frames, + (int16_t *)out->buffer, + &out_frames); + ret = pcm_mmap_write(out->pcm[PCM_NORMAL], (void *)out->buffer, out_frames * frame_size); + } else + ret = pcm_mmap_write(out->pcm[PCM_NORMAL], (void *)buffer, bytes); + +exit: + pthread_mutex_unlock(&out->lock); + + if (ret != 0) { + usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / + out_get_sample_rate(&stream->common)); + } + + return bytes; +} + static int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) { @@ -2803,6 +2889,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, struct tuna_audio_device *ladev = (struct tuna_audio_device *)dev; struct tuna_stream_out *out; int ret; + int output_type; *stream_out = NULL; @@ -2810,6 +2897,24 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (!out) return -ENOMEM; + if (flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) { + ALOGV("adev_open_output_stream() deep buffer"); + if (ladev->outputs[OUTPUT_DEEP_BUF] != NULL) + return -ENOSYS; + output_type = OUTPUT_DEEP_BUF; + out->stream.common.get_buffer_size = out_get_buffer_size_deep_buffer; + out->stream.get_latency = out_get_latency_deep_buffer; + out->stream.write = out_write_deep_buffer; + } else { + ALOGV("adev_open_output_stream() normal buffer"); + if (ladev->outputs[OUTPUT_LOW_LATENCY] != NULL) + return -ENOSYS; + output_type = OUTPUT_LOW_LATENCY; + out->stream.common.get_buffer_size = out_get_buffer_size_low_latency; + out->stream.get_latency = out_get_latency_low_latency; + out->stream.write = out_write_low_latency; + } + ret = create_resampler(DEFAULT_OUT_SAMPLING_RATE, MM_FULL_POWER_SAMPLING_RATE, 2, @@ -2818,11 +2923,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, &out->resampler); if (ret != 0) goto err_open; - out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */ out->stream.common.get_sample_rate = out_get_sample_rate; out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; out->stream.common.get_channels = out_get_channels; out->stream.common.get_format = out_get_format; out->stream.common.set_format = out_set_format; @@ -2832,9 +2935,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.common.get_parameters = out_get_parameters; out->stream.common.add_audio_effect = out_add_audio_effect; out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; out->stream.set_volume = out_set_volume; - out->stream.write = out_write; out->stream.get_render_position = out_get_render_position; out->dev = ladev; @@ -2853,6 +2954,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, config->sample_rate = out_get_sample_rate(&out->stream.common); *stream_out = &out->stream; + ladev->outputs[output_type] = out; + return 0; err_open: @@ -2863,9 +2966,18 @@ err_open: static void adev_close_output_stream(struct audio_hw_device *dev, struct audio_stream_out *stream) { + struct tuna_audio_device *ladev = (struct tuna_audio_device *)dev; struct tuna_stream_out *out = (struct tuna_stream_out *)stream; + int i; out_standby(&stream->common); + for (i = 0; i < OUTPUT_TOTAL; i++) { + if (ladev->outputs[i] == out) { + ladev->outputs[i] = NULL; + break; + } + } + if (out->buffer) free(out->buffer); if (out->resampler) @@ -2914,14 +3026,6 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->bluetooth_nrec = false; } - ret = str_parms_get_str(parms, "screen_state", value, sizeof(value)); - if (ret >= 0) { - if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) - adev->low_power = false; - else - adev->low_power = true; - } - str_parms_destroy(parms); return ret; } @@ -3192,10 +3296,14 @@ static int adev_open(const hw_module_t* module, const char* name, MIXER_DL1_MIXER_MULTIMEDIA); adev->mixer_ctls.vx_dl1 = mixer_get_ctl_by_name(adev->mixer, MIXER_DL1_MIXER_VOICE); + adev->mixer_ctls.tones_dl1 = mixer_get_ctl_by_name(adev->mixer, + MIXER_DL1_MIXER_TONES); adev->mixer_ctls.mm_dl2 = mixer_get_ctl_by_name(adev->mixer, MIXER_DL2_MIXER_MULTIMEDIA); adev->mixer_ctls.vx_dl2 = mixer_get_ctl_by_name(adev->mixer, MIXER_DL2_MIXER_VOICE); + adev->mixer_ctls.tones_dl2 = mixer_get_ctl_by_name(adev->mixer, + MIXER_DL2_MIXER_TONES); adev->mixer_ctls.dl2_mono = mixer_get_ctl_by_name(adev->mixer, MIXER_DL2_MONO_MIXER); adev->mixer_ctls.dl1_headset = mixer_get_ctl_by_name(adev->mixer, @@ -3223,8 +3331,9 @@ static int adev_open(const hw_module_t* module, const char* name, if (!adev->mixer_ctls.dl1_eq || !adev->mixer_ctls.vx_dl2_volume || !adev->mixer_ctls.mm_dl2_volume || !adev->mixer_ctls.mm_dl1 || - !adev->mixer_ctls.vx_dl1 || !adev->mixer_ctls.mm_dl2 || - !adev->mixer_ctls.vx_dl2 || !adev->mixer_ctls.dl2_mono || + !adev->mixer_ctls.vx_dl1 || !adev->mixer_ctls.tones_dl1 || + !adev->mixer_ctls.mm_dl2 || !adev->mixer_ctls.vx_dl2 || + !adev->mixer_ctls.tones_dl2 ||!adev->mixer_ctls.dl2_mono || !adev->mixer_ctls.dl1_headset || !adev->mixer_ctls.dl1_bt || !adev->mixer_ctls.earpiece_enable || !adev->mixer_ctls.left_capture || !adev->mixer_ctls.right_capture || !adev->mixer_ctls.amic_ul_volume || diff --git a/audio/audio_policy.conf b/audio/audio_policy.conf index 1e30270..a2971b0 100644 --- a/audio/audio_policy.conf +++ b/audio/audio_policy.conf @@ -29,6 +29,13 @@ audio_hw_modules { devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET flags AUDIO_OUTPUT_FLAG_PRIMARY } + deep_buffer { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE + flags AUDIO_OUTPUT_FLAG_DEEP_BUFFER + } } inputs { primary { |