hal: qaf: Add support for Dual Main playback
Add support for Dual Main playback
Change-Id: I26c8f35d6284c280c25a5b27ed5503a2873ed407
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index caf64ee..f16c365 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -36,6 +36,7 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#define DEBUG_MSG_VV(arg,...) ALOGVV("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
#define DEBUG_MSG(arg,...) ALOGV("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
#define ERROR_MSG(arg,...) ALOGE("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
@@ -58,6 +59,7 @@
#define QAF_MODULE_PCM_INPUT_BUFFER_LATENCY 32
#define MS12_PCM_OUT_FRAGMENT_SIZE 1536 //samples
+#define MS12_PCM_IN_FRAGMENT_SIZE 1536 //samples
#define DD_FRAME_SIZE 1536
#define DDP_FRAME_SIZE DD_FRAME_SIZE
@@ -147,9 +149,9 @@
typedef enum {
QAF_IN_MAIN = 0, /* Single PID Main/Primary or Dual-PID stream */
- QAF_IN_ASSOC, /* Associated/Secondary stream */
- QAF_IN_PCM, /* PCM stream. */
-
+ QAF_IN_ASSOC, /* Associated/Secondary stream */
+ QAF_IN_PCM, /* PCM stream. */
+ QAF_IN_MAIN_2, /* Single PID Main2 stream */
MAX_QAF_MODULE_IN
} mm_module_input_type;
@@ -305,6 +307,16 @@
}
}
+static bool is_main_active(struct qaf_module* qaf_mod)
+{
+ return (qaf_mod->stream_in[QAF_IN_MAIN] || qaf_mod->stream_in[QAF_IN_MAIN_2]);
+}
+
+static bool is_dual_main_active(struct qaf_module* qaf_mod)
+{
+ return (qaf_mod->stream_in[QAF_IN_MAIN] && qaf_mod->stream_in[QAF_IN_MAIN_2]);
+}
+
/* Gets the pcm output buffer size(in samples) for the mm module. */
static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
{
@@ -491,7 +503,7 @@
/* Sends a command to output stream offload thread. */
static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
{
- DEBUG_MSG("command is %d", command);
+ DEBUG_MSG_VV("command is %d", command);
struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
@@ -637,7 +649,6 @@
{
int ret = -EINVAL;
struct qaf_module *qaf_mod = NULL;
- DEBUG_MSG("bytes = %d [%p]", bytes, out->qaf_stream_handle);
qaf_mod = get_qaf_module_for_input_stream(out);
if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_write)) {
@@ -657,7 +668,7 @@
struct audio_device *adev = out->dev;
ssize_t ret = 0;
- DEBUG_MSG("bytes = %d, usecase[%d] and flags[%x] for handle[%p]",
+ DEBUG_MSG_VV("bytes = %d, usecase[%d] and flags[%x] for handle[%p]",
(int)bytes, out->usecase, out->flags, out);
lock_output_stream(out);
@@ -691,7 +702,7 @@
}
ret = qaf_module_write_input_buffer(out, buffer, bytes);
- DEBUG_MSG("ret [%d]", (int)ret);
+ DEBUG_MSG_VV("ret [%d]", (int)ret);
if (ret >= 0) {
bytes = ret;
@@ -704,7 +715,7 @@
if (ret < 0) {
if (ret == -EAGAIN) {
- DEBUG_MSG("No space available in mm module, post msg to cb thread");
+ DEBUG_MSG_VV("No space available in mm module, post msg to cb thread");
ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
bytes = 0;
} else if (ret == -ENOMEM || ret == -EPERM) {
@@ -719,11 +730,10 @@
return bytes;
}
-/* Gets PCM offload buffer size for QAF module output. */
-static uint32_t qaf_get_pcm_offload_buffer_size(struct qaf_module *qaf_mod,
- audio_offload_info_t* info)
+/* Gets PCM offload buffer size for a given config. */
+static uint32_t qaf_get_pcm_offload_buffer_size(audio_offload_info_t* info,
+ uint32_t samples_per_frame)
{
- uint32_t samples_per_frame = get_pcm_output_buffer_size_samples(qaf_mod);
uint32_t fragment_size = 0;
fragment_size = (samples_per_frame * (info->bit_width >> 3) * popcount(info->channel_mask));
@@ -739,11 +749,22 @@
fragment_size = ALIGN(fragment_size,
((info->bit_width >> 3) * popcount(info->channel_mask) * 32));
- ALOGI("Qaf PCM offload Fragment size to %d bytes", fragment_size);
+ ALOGI("Qaf PCM offload Fragment size is %d bytes", fragment_size);
return fragment_size;
}
+static uint32_t qaf_get_pcm_offload_input_buffer_size(info)
+{
+ return qaf_get_pcm_offload_buffer_size(info, MS12_PCM_IN_FRAGMENT_SIZE);
+}
+
+static uint32_t qaf_get_pcm_offload_output_buffer_size(struct qaf_module *qaf_mod,
+ audio_offload_info_t* info)
+{
+ return qaf_get_pcm_offload_buffer_size(info, get_pcm_output_buffer_size_samples(qaf_mod));
+}
+
/* Gets buffer latency in samples. */
static int get_buffer_latency(struct stream_out *out, uint32_t buffer_size, uint32_t *latency)
{
@@ -1047,7 +1068,7 @@
struct stream_out *out = (struct stream_out *)stream;
uint32_t latency = 0;
struct qaf_module *qaf_mod = NULL;
- DEBUG_MSG("Output Stream %p", out);
+ DEBUG_MSG_VV("Output Stream %p", out);
qaf_mod = get_qaf_module_for_input_stream(out);
if (!qaf_mod) {
@@ -1091,7 +1112,7 @@
}
}
- DEBUG_MSG("Latency %d", latency);
+ DEBUG_MSG_VV("Latency %d", latency);
return latency;
}
@@ -1139,12 +1160,10 @@
struct audio_stream_out *bt_stream = NULL;
int format;
- DEBUG_MSG("Device 0x%X, Event = 0x%X", device, event_id);
+ DEBUG_MSG_VV("Device 0x%X, Event = 0x%X, Bytes to write %d", device, event_id, size);
pthread_mutex_lock(&p_qaf->lock);
if (event_id == AUDIO_DATA_EVENT) {
- DEBUG_MSG("Device id 0x%X, bytes to write %d", device, size);
-
if (p_qaf->passthrough_out != NULL) {
//If QAF passthrough is active then all the module output will be dropped.
pthread_mutex_unlock(&p_qaf->lock);
@@ -1284,17 +1303,27 @@
qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
COMPRESS_OFFLOAD_NUM_FRAGMENTS;
qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
- qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+ qaf_get_pcm_offload_output_buffer_size(qaf_mod, &config.offload_info);
p_qaf->mch_pcm_hdmi_enabled = true;
- if (qaf_mod->stream_in[QAF_IN_MAIN]
- && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
+ if ((qaf_mod->stream_in[QAF_IN_MAIN]
+ && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) ||
+ (qaf_mod->stream_in[QAF_IN_MAIN_2]
+ && qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback != NULL)) {
- qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+ if (qaf_mod->stream_in[QAF_IN_MAIN]) {
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
(struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+ }
+ if (qaf_mod->stream_in[QAF_IN_MAIN_2]) {
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
+ qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback,
+ qaf_mod->stream_in[QAF_IN_MAIN_2]->client_cookie);
+ }
} else if (qaf_mod->stream_in[QAF_IN_PCM]
&& qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
@@ -1307,6 +1336,8 @@
int index = -1;
if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
index = (int) QAF_IN_MAIN;
+ else if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN_2].adsp_hdlr_config_valid)
+ index = (int) QAF_IN_MAIN_2;
else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
index = (int) QAF_IN_PCM;
@@ -1389,13 +1420,23 @@
return;
}
- if (qaf_mod->stream_in[QAF_IN_MAIN]
- && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
+ if ((qaf_mod->stream_in[QAF_IN_MAIN]
+ && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) ||
+ (qaf_mod->stream_in[QAF_IN_MAIN_2]
+ && qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback != NULL)) {
- qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+ if (qaf_mod->stream_in[QAF_IN_MAIN]) {
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
(struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
+ }
+ if (qaf_mod->stream_in[QAF_IN_MAIN_2]) {
+ qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
+ (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
+ qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback,
+ qaf_mod->stream_in[QAF_IN_MAIN_2]->client_cookie);
+ }
} else if (qaf_mod->stream_in[QAF_IN_PCM]
&& qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
@@ -1408,7 +1449,7 @@
qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
COMPRESS_OFFLOAD_NUM_FRAGMENTS;
qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
- qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
+ qaf_get_pcm_offload_output_buffer_size(qaf_mod, &config.offload_info);
if (qaf_mod->is_vol_set) {
DEBUG_MSG("Setting Volume Left[%f], Right[%f]", qaf_mod->vol_left, qaf_mod->vol_right);
@@ -1421,6 +1462,8 @@
int index = -1;
if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
index = (int) QAF_IN_MAIN;
+ else if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN_2].adsp_hdlr_config_valid)
+ index = (int) QAF_IN_MAIN_2;
else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
index = (int) QAF_IN_PCM;
if (index >= 0) {
@@ -1449,16 +1492,18 @@
size);
}
}
-
- DEBUG_MSG("Bytes written = %d", ret);
+ DEBUG_MSG_VV("Bytes written = %d", ret);
}
else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
+ || event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
|| event_id == AUDIO_EOS_MAIN_AAC_EVENT
|| event_id == AUDIO_EOS_MAIN_AC4_EVENT
|| event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
+ struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
bool *main_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
+ bool *main2_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN_2];
bool *assoc_drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
/**
@@ -1474,6 +1519,15 @@
*assoc_drain_received = false;
unlock_output_stream(out_assoc);
DEBUG_MSG("sent associated DRAIN_READY");
+ } else if (event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
+ && (out_main2 != NULL)
+ && (*main2_drain_received)) {
+
+ lock_output_stream(out_main2);
+ out_main2->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_main2->client_cookie);
+ *main2_drain_received = false;
+ unlock_output_stream(out_main2);
+ DEBUG_MSG("sent main2 DRAIN_READY");
} else if ((out != NULL) && (*main_drain_received)) {
lock_output_stream(out);
out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
@@ -1718,44 +1772,61 @@
devices,
AUDIO_STREAM_SYSTEM_TONE);
qaf_mod->stream_in[QAF_IN_PCM] = out;
- } else {
- if (!qaf_mod->stream_in[QAF_IN_MAIN]) {
- if ((!(flags & AUDIO_OUTPUT_FLAG_MAIN)) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
- ERROR_MSG("Error main input is not active.");
- return -EINVAL;
- }
-
- status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
- &out->qaf_stream_handle,
- input_config,
- devices,
- AUDIO_STREAM_MAIN);
- if (status == 0) {
- DEBUG_MSG("Open stream for Input with Main stream contents with flag [%x] and stream handle [%p]",
- flags, out->qaf_stream_handle);
- qaf_mod->stream_in[QAF_IN_MAIN] = out;
- }
+ } else if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
+ if (is_main_active(qaf_mod) || is_dual_main_active(qaf_mod)) {
+ ERROR_MSG("Dual Main or Main already active. So, Cannot open main and associated stream");
+ return -EINVAL;
} else {
- if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
- ERROR_MSG("Error main input is already active");
- return -EINVAL;
- } else if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)
- && (!qaf_mod->stream_in[QAF_IN_ASSOC])) {
- status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
- &out->qaf_stream_handle,
- input_config,
- devices,
- AUDIO_STREAM_ASSOCIATED);
- if (status == 0) {
- DEBUG_MSG("Open stream for Input with only Associated flag [%x] stream handle [%p]",
- flags, out->qaf_stream_handle);
- qaf_mod->stream_in[QAF_IN_ASSOC] = out;
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
+ if (status == 0) {
+ DEBUG_MSG("Open stream for Input with both Main and Associated stream contents with flag(%x) and stream_handle(%p)", flags, out->qaf_stream_handle);
+ qaf_mod->stream_in[QAF_IN_MAIN] = out;
+ } else {
+ ERROR_MSG("Stream Open FAILED !!!");
+ }
+ }
+ } else if ((flags & AUDIO_OUTPUT_FLAG_MAIN) || (!((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)))) {
+ /* Assume Main if no flag is set */
+ if (is_dual_main_active(qaf_mod)) {
+ ERROR_MSG("Dual Main already active. So, Cannot open main stream");
+ return -EINVAL;
+ } else if (is_main_active(qaf_mod) && qaf_mod->stream_in[QAF_IN_ASSOC]) {
+ ERROR_MSG("Main and Associated already active. So, Cannot open main stream");
+ return -EINVAL;
+ } else if (is_main_active(qaf_mod) && (mmtype != MS12)) {
+ ERROR_MSG("Main already active and Not an MS12 format. So, Cannot open another main stream");
+ return -EINVAL;
+ } else {
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
+ if (status == 0) {
+ DEBUG_MSG("Open stream for Input with only Main flag(%x) stream_handle(%p)", flags, out->qaf_stream_handle);
+ if(qaf_mod->stream_in[QAF_IN_MAIN]) {
+ qaf_mod->stream_in[QAF_IN_MAIN_2] = out;
+ } else {
+ qaf_mod->stream_in[QAF_IN_MAIN] = out;
}
} else {
- ERROR_MSG("Invalid flag or associated is already active");
- status = -EINVAL;
+ ERROR_MSG("Stream Open FAILED !!!");
}
}
+ } else if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
+ if (is_dual_main_active(qaf_mod)) {
+ ERROR_MSG("Dual Main already active. So, Cannot open associated stream");
+ return -EINVAL;
+ } else if (!is_main_active(qaf_mod)) {
+ ERROR_MSG("Main not active. So, Cannot open associated stream");
+ return -EINVAL;
+ } else if (qaf_mod->stream_in[QAF_IN_ASSOC]) {
+ ERROR_MSG("Associated already active. So, Cannot open associated stream");
+ return -EINVAL;
+ }
+ status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
+ if (status == 0) {
+ DEBUG_MSG("Open stream for Input with only Associated flag(%x) stream handle(%p)", flags, out->qaf_stream_handle);
+ qaf_mod->stream_in[QAF_IN_ASSOC] = out;
+ } else {
+ ERROR_MSG("Stream Open FAILED !!!");
+ }
}
if (status != 0) {
@@ -1849,11 +1920,11 @@
stream_callback_event_t event;
bool send_callback = false;
- DEBUG_MSG("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
+ DEBUG_MSG_VV("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
if (list_empty(&out->qaf_offload_cmd_list)) {
- DEBUG_MSG("SLEEPING");
+ DEBUG_MSG_VV("SLEEPING");
pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
- DEBUG_MSG("RUNNING");
+ DEBUG_MSG_VV("RUNNING");
continue;
}
@@ -1871,7 +1942,7 @@
send_callback = false;
switch (cmd->cmd) {
case OFFLOAD_CMD_WAIT_FOR_BUFFER: {
- DEBUG_MSG("wait for buffer availability");
+ DEBUG_MSG_VV("wait for buffer availability");
while (1) {
kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle,
@@ -1881,12 +1952,12 @@
ret = str_parms_get_int(parms, "buf_available", &value);
if (ret >= 0) {
if (value >= (int)out->compr_config.fragment_size) {
- DEBUG_MSG("buffer available");
+ DEBUG_MSG_VV("buffer available");
str_parms_destroy(parms);
parms = NULL;
break;
} else {
- DEBUG_MSG("sleep");
+ DEBUG_MSG_VV("sleep");
str_parms_destroy(parms);
parms = NULL;
usleep(10000);
@@ -1978,11 +2049,7 @@
/* Setting new device information to the mm module input streams.
* This is needed if QAF module output streams are not created yet.
*/
- if (qaf_mod->stream_in[QAF_IN_MAIN] == out || qaf_mod->stream_in[QAF_IN_ASSOC] == out) {
- qaf_mod->stream_in[QAF_IN_MAIN]->devices = val;
- } else {
- out->devices = val;
- }
+ out->devices = val;
if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
//If device is BT then open the BT stream if not already opened.
@@ -2214,7 +2281,10 @@
out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
out->config.start_threshold = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
out->config.avail_min = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
+ } else if(out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
+ out->compr_config.fragment_size = qaf_get_pcm_offload_input_buffer_size(&(config->offload_info));
}
+
*stream_out = &out->stream;
if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
qaf_create_offload_callback_thread(out);