blob: ca83b1dd6f302b9185e12b82d87b36b88aca9612 [file] [log] [blame]
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301/*
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +05302 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05303 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define LOG_TAG "audio_hw_qaf"
31/*#define LOG_NDEBUG 0*/
32/*#define VERY_VERY_VERBOSE_LOGGING*/
33#ifdef VERY_VERY_VERBOSE_LOGGING
Harsh Bansal6bf3b4d2017-08-24 11:16:13 +053034#define DEBUG_MSG_VV DEBUG_MSG
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053035#else
Harsh Bansal6bf3b4d2017-08-24 11:16:13 +053036#define DEBUG_MSG_VV(a...) do { } while(0)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053037#endif
38
Harsh Bansal28718c52017-04-20 13:47:12 +053039#define DEBUG_MSG(arg,...) ALOGV("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
40#define ERROR_MSG(arg,...) ALOGE("%s: %d: " arg, __func__, __LINE__, ##__VA_ARGS__)
41
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053042#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 2
Harsh Bansal28718c52017-04-20 13:47:12 +053043#define COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE 4608
44
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053045#define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
46#define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053047#define QAF_DEFAULT_PASSTHROUGH_HANDLE 1003
Ben Rombergerd771a7c2017-02-22 18:05:17 -080048
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053049#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 300
Varun B34da7a42017-02-13 16:16:53 +053050
Varun B34da7a42017-02-13 16:16:53 +053051#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
52#define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
53
54#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
55#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
56
57/* Pcm input node buffer size is 6144 bytes, i.e, 32msec for 48000 samplerate */
Harsh Bansal28718c52017-04-20 13:47:12 +053058#define QAF_MODULE_PCM_INPUT_BUFFER_LATENCY 32
Varun B34da7a42017-02-13 16:16:53 +053059
Harsh Bansal28718c52017-04-20 13:47:12 +053060#define MS12_PCM_OUT_FRAGMENT_SIZE 1536 //samples
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +053061#define MS12_PCM_IN_FRAGMENT_SIZE 1536 //samples
Varun B34da7a42017-02-13 16:16:53 +053062
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053063#define DD_FRAME_SIZE 1536
Harsh Bansal28718c52017-04-20 13:47:12 +053064#define DDP_FRAME_SIZE DD_FRAME_SIZE
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053065/*
Harsh Bansal28718c52017-04-20 13:47:12 +053066 * DD encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053067 */
68#define DD_ENCODER_OUTPUT_SIZE 2560
69/*
Harsh Bansal28718c52017-04-20 13:47:12 +053070 * DDP encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053071 */
72#define DDP_ENCODER_OUTPUT_SIZE 4608
73
Harsh Bansal28718c52017-04-20 13:47:12 +053074/*********TODO Need to get correct values.*************************/
75
76#define DTS_PCM_OUT_FRAGMENT_SIZE 1024 //samples
77
78#define DTS_FRAME_SIZE 1536
79#define DTSHD_FRAME_SIZE DTS_FRAME_SIZE
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053080/*
Harsh Bansal28718c52017-04-20 13:47:12 +053081 * DTS encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053082 */
Harsh Bansal28718c52017-04-20 13:47:12 +053083#define DTS_ENCODER_OUTPUT_SIZE 2560
84/*
85 * DTSHD encoder output size for one frame.
86 */
87#define DTSHD_ENCODER_OUTPUT_SIZE 4608
88/******************************************************************/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053089
Bharath Gopal01310bb2016-12-05 15:39:32 +053090/*
91 * QAF Latency to process buffers since out_write from primary HAL
92 */
93#define QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY 18
94#define QAF_PCM_OFFLOAD_PROCESSING_LATENCY 48
95
Harsh Bansal28718c52017-04-20 13:47:12 +053096//TODO: Need to handle for DTS
Varun B34da7a42017-02-13 16:16:53 +053097#define QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1536
98
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053099#include <stdlib.h>
100#include <pthread.h>
101#include <errno.h>
102#include <dlfcn.h>
103#include <sys/resource.h>
104#include <sys/prctl.h>
105#include <cutils/properties.h>
106#include <cutils/str_parms.h>
107#include <cutils/log.h>
108#include <cutils/atomic.h>
109#include "audio_utils/primitives.h"
110#include "audio_hw.h"
111#include "platform_api.h"
112#include <platform.h>
113#include <system/thread_defs.h>
114#include <cutils/sched_policy.h>
115#include "audio_extn.h"
116#include <qti_audio.h>
117#include "sound/compress_params.h"
118
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +0530119#ifdef DYNAMIC_LOG_ENABLED
120#include <log_xml_parser.h>
121#define LOG_MASK HAL_MOD_FILE_QAF
122#include <log_utils.h>
123#endif
124
Harsh Bansal28718c52017-04-20 13:47:12 +0530125//TODO: Need to remove this.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530126#define QAF_OUTPUT_SAMPLING_RATE 48000
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530127
128#ifdef QAF_DUMP_ENABLED
129FILE *fp_output_writer_hdmi = NULL;
130#endif
131
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800132struct qaf_adsp_hdlr_config_state {
133 struct audio_adsp_event event_params;
134 /* For holding client audio_adsp_event payload */
135 uint8_t event_payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN];
136 bool adsp_hdlr_config_valid;
137};
138
Harsh Bansal28718c52017-04-20 13:47:12 +0530139//Types of MM module, currently supported by QAF.
140typedef enum {
141 MS12,
142 DTS_M8,
143 MAX_MM_MODULE_TYPE,
144 INVALID_MM_MODULE
145} mm_module_type;
146
147typedef enum {
148 QAF_OUT_TRANSCODE_PASSTHROUGH = 0, /* Transcode passthrough via MM module*/
149 QAF_OUT_OFFLOAD_MCH, /* Multi-channel PCM offload*/
150 QAF_OUT_OFFLOAD, /* PCM offload */
151
152 MAX_QAF_MODULE_OUT
153} mm_module_output_type;
154
155typedef enum {
156 QAF_IN_MAIN = 0, /* Single PID Main/Primary or Dual-PID stream */
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530157 QAF_IN_ASSOC, /* Associated/Secondary stream */
158 QAF_IN_PCM, /* PCM stream. */
159 QAF_IN_MAIN_2, /* Single PID Main2 stream */
Harsh Bansal28718c52017-04-20 13:47:12 +0530160 MAX_QAF_MODULE_IN
161} mm_module_input_type;
162
Harsh Bansal9a376832017-06-08 20:18:06 +0530163typedef enum {
164 STOPPED, /*Stream is in stop state. */
165 STOPPING, /*Stream is stopping, waiting for EOS. */
166 RUN, /*Stream is in run state. */
167 MAX_STATES
168} qaf_stream_state;
169
Harsh Bansal28718c52017-04-20 13:47:12 +0530170struct qaf_module {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530171 audio_session_handle_t session_handle;
Vidyakumar Athota4f392512017-05-15 18:03:40 -0700172 void *ip_hdlr_hdl;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530173 void *qaf_lib;
Harsh Bansal28718c52017-04-20 13:47:12 +0530174 int (*qaf_audio_session_open)(audio_session_handle_t* session_handle,
Sri Karri1fbfef52017-06-29 19:45:47 +0530175 audio_session_type_t s_type,
Harsh Bansal28718c52017-04-20 13:47:12 +0530176 void *p_data,
177 void* license_data);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530178 int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
Harsh Bansal28718c52017-04-20 13:47:12 +0530179 int (*qaf_audio_stream_open)(audio_session_handle_t session_handle,
180 audio_stream_handle_t* stream_handle,
181 audio_stream_config_t input_config,
182 audio_devices_t devices,
183 stream_type_t flags);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530184 int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
185 int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
186 int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
187 char* (*qaf_audio_stream_get_param)(audio_stream_handle_t stream_handle, const char* key);
188 char* (*qaf_audio_session_get_param)(audio_session_handle_t handle, const char* key);
189 int (*qaf_audio_stream_start)(audio_stream_handle_t handle);
190 int (*qaf_audio_stream_stop)(audio_stream_handle_t stream_handle);
191 int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
192 int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
193 int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
Harsh Bansal28718c52017-04-20 13:47:12 +0530194 void (*qaf_register_event_callback)(audio_session_handle_t session_handle,
195 void *priv_data,
196 notify_event_callback_t event_callback,
197 audio_event_id_t event_id);
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800198
Harsh Bansal28718c52017-04-20 13:47:12 +0530199 /*Input stream of MM module */
200 struct stream_out *stream_in[MAX_QAF_MODULE_IN];
201 /*Output Stream from MM module */
202 struct stream_out *stream_out[MAX_QAF_MODULE_OUT];
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800203
Harsh Bansal431eede2017-04-28 21:22:30 +0530204 /*Media format associated with each output id raised by mm module. */
205 audio_qaf_media_format_t out_stream_fmt[MAX_QAF_MODULE_OUT];
206 /*Flag is set if media format is changed for an mm module output. */
207 bool is_media_fmt_changed[MAX_QAF_MODULE_OUT];
208 /*Index to be updated in out_stream_fmt array for a new mm module output. */
209 int new_out_format_index;
210
Harsh Bansal28718c52017-04-20 13:47:12 +0530211 struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_MODULE_IN];
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800212
Harsh Bansal28718c52017-04-20 13:47:12 +0530213 //BT session handle.
Bharath Gopal01310bb2016-12-05 15:39:32 +0530214 void *bt_hdl;
Harsh Bansal28718c52017-04-20 13:47:12 +0530215
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530216 float vol_left;
217 float vol_right;
Harsh Bansal28718c52017-04-20 13:47:12 +0530218 bool is_vol_set;
Harsh Bansal9a376832017-06-08 20:18:06 +0530219 qaf_stream_state stream_state[MAX_QAF_MODULE_IN];
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530220};
221
Harsh Bansal28718c52017-04-20 13:47:12 +0530222struct qaf {
223 struct audio_device *adev;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530224
Harsh Bansal28718c52017-04-20 13:47:12 +0530225 pthread_mutex_t lock;
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800226
Harsh Bansal28718c52017-04-20 13:47:12 +0530227 bool hdmi_connect;
228 int hdmi_sink_channels;
229
230 //Flag to indicate if QAF transcode output stream is enabled from any mm module.
231 bool passthrough_enabled;
232 //Flag to indicate if QAF mch pcm output stream is enabled from any mm module.
233 bool mch_pcm_hdmi_enabled;
234
235 //Flag to indicate if msmd is supported.
236 bool qaf_msmd_enabled;
237
238 //Handle of QAF input stream, which is routed as QAF passthrough.
239 struct stream_out *passthrough_in;
240 //Handle of QAF passthrough stream.
241 struct stream_out *passthrough_out;
242
243 struct qaf_module qaf_mod[MAX_MM_MODULE_TYPE];
244};
245
246static int qaf_out_pause(struct audio_stream_out* stream);
247static int qaf_out_flush(struct audio_stream_out* stream);
248static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type);
Vidyakumar Athota4f392512017-05-15 18:03:40 -0700249static int qaf_session_close();
Harsh Bansal28718c52017-04-20 13:47:12 +0530250
251//Global handle of QAF. Access to this should be protected by mutex lock.
252static struct qaf *p_qaf = NULL;
253
254/* Gets the pointer to qaf module for the qaf input stream. */
255static struct qaf_module* get_qaf_module_for_input_stream(struct stream_out *out)
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530256{
Harsh Bansal28718c52017-04-20 13:47:12 +0530257 struct qaf_module *qaf_mod = NULL;
258 int i, j;
259 if (!p_qaf) return NULL;
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530260
Harsh Bansal28718c52017-04-20 13:47:12 +0530261 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
262 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
263 if (p_qaf->qaf_mod[i].stream_in[j] == out) {
264 qaf_mod = &(p_qaf->qaf_mod[i]);
265 break;
266 }
267 }
268 }
269
270 return qaf_mod;
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530271}
272
Harsh Bansal28718c52017-04-20 13:47:12 +0530273/* Finds the mm module input stream index for the QAF input stream. */
274static int get_input_stream_index(struct stream_out *out)
275{
276 int index = -1, j;
277 struct qaf_module* qaf_mod = NULL;
278
279 qaf_mod = get_qaf_module_for_input_stream(out);
280 if (!qaf_mod) return index;
281
282 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
283 if (qaf_mod->stream_in[j] == out) {
284 index = j;
285 break;
286 }
287 }
288
289 return index;
290}
291
Harsh Bansal9a376832017-06-08 20:18:06 +0530292static void set_stream_state(struct stream_out *out, int state)
293{
294 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
295 int index = get_input_stream_index(out);
296 if (qaf_mod && index >= 0) qaf_mod->stream_state[index] = state;
297}
298
299static bool check_stream_state(struct stream_out *out, int state)
300{
301 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
302 int index = get_input_stream_index(out);
303 if (qaf_mod && index >= 0) return (qaf_mod->stream_state[index] == state);
304 return false;
305}
306
Harsh Bansal28718c52017-04-20 13:47:12 +0530307/* Finds the right mm module for the QAF input stream format. */
308static mm_module_type get_mm_module_for_format(audio_format_t format)
309{
310 int j;
311
312 DEBUG_MSG("Format 0x%x", format);
313
314 if (format == AUDIO_FORMAT_PCM_16_BIT) {
315 //If dts is not supported then alway support pcm with MS12
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700316 if (!property_get_bool("vendor.audio.qaf.dts_m8", false)) { //TODO: Need to add this property for DTS.
Harsh Bansal28718c52017-04-20 13:47:12 +0530317 return MS12;
318 }
319
320 //If QAF passthrough is active then send the PCM stream to primary HAL.
321 if (!p_qaf->passthrough_out) {
322 /* Iff any stream is active in MS12 module then route PCM stream to it. */
323 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
324 if (p_qaf->qaf_mod[MS12].stream_in[j]) {
325 return MS12;
326 }
327 }
328 }
329 return INVALID_MM_MODULE;
330 }
331
332 switch (format & AUDIO_FORMAT_MAIN_MASK) {
333 case AUDIO_FORMAT_AC3:
334 case AUDIO_FORMAT_E_AC3:
335 case AUDIO_FORMAT_AAC:
336 case AUDIO_FORMAT_AAC_ADTS:
337 case AUDIO_FORMAT_AC4:
338 return MS12;
339 case AUDIO_FORMAT_DTS:
340 case AUDIO_FORMAT_DTS_HD:
341 return DTS_M8;
342 default:
343 return INVALID_MM_MODULE;
344 }
345}
346
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530347static bool is_main_active(struct qaf_module* qaf_mod)
348{
349 return (qaf_mod->stream_in[QAF_IN_MAIN] || qaf_mod->stream_in[QAF_IN_MAIN_2]);
350}
351
352static bool is_dual_main_active(struct qaf_module* qaf_mod)
353{
354 return (qaf_mod->stream_in[QAF_IN_MAIN] && qaf_mod->stream_in[QAF_IN_MAIN_2]);
355}
356
Harsh Bansal0345a202017-08-31 18:42:18 +0530357//Checks if any main or pcm stream is running in the session.
358static bool is_any_stream_running(struct qaf_module* qaf_mod)
359{
360 //Not checking associated stream.
361 struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
362 struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
363 struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
364
365 if ((out == NULL || (out != NULL && check_stream_state(out, STOPPED)))
366 && (out_main2 == NULL || (out_main2 != NULL && check_stream_state(out_main2, STOPPED)))
367 && (out_pcm == NULL || (out_pcm != NULL && check_stream_state(out_pcm, STOPPED)))) {
368 return false;
369 }
370 return true;
371}
372
Harsh Bansal28718c52017-04-20 13:47:12 +0530373/* Gets the pcm output buffer size(in samples) for the mm module. */
374static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
375{
376 uint32_t pcm_output_buffer_size = 0;
377
378 if (qaf_mod == &p_qaf->qaf_mod[MS12]) {
379 pcm_output_buffer_size = MS12_PCM_OUT_FRAGMENT_SIZE;
380 } else if (qaf_mod == &p_qaf->qaf_mod[DTS_M8]) {
381 pcm_output_buffer_size = DTS_PCM_OUT_FRAGMENT_SIZE;
382 }
383
384 return pcm_output_buffer_size;
385}
386
Harsh Bansal431eede2017-04-28 21:22:30 +0530387static int get_media_fmt_array_index_for_output_id(
388 struct qaf_module* qaf_mod,
389 int output_id)
390{
391 int i;
392 for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
393 if (qaf_mod->out_stream_fmt[i].output_id == output_id) {
394 return i;
395 }
396 }
397 return -1;
398}
399
Harsh Bansal28718c52017-04-20 13:47:12 +0530400/* Acquire Mutex lock on output stream */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530401static void lock_output_stream(struct stream_out *out)
402{
403 pthread_mutex_lock(&out->pre_lock);
404 pthread_mutex_lock(&out->lock);
405 pthread_mutex_unlock(&out->pre_lock);
406}
407
Harsh Bansal28718c52017-04-20 13:47:12 +0530408/* Release Mutex lock on output stream */
409static void unlock_output_stream(struct stream_out *out)
410{
411 pthread_mutex_unlock(&out->lock);
412}
413
414/* Checks if stream can be routed as QAF passthrough or not. */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530415static bool audio_extn_qaf_passthrough_enabled(struct stream_out *out)
416{
Harsh Bansal28718c52017-04-20 13:47:12 +0530417 DEBUG_MSG("Format 0x%x", out->format);
418 bool is_enabled = false;
419
420 if (!p_qaf) return false;
421
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700422 if ((!property_get_bool("vendor.audio.qaf.reencode", false))
423 && property_get_bool("vendor.audio.qaf.passthrough", false)) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530424
425 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
426 is_enabled = true;
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700427 } else if (property_get_bool("vendor.audio.offload.passthrough", false)) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530428 switch (out->format) {
429 case AUDIO_FORMAT_AC3:
430 case AUDIO_FORMAT_E_AC3:
431 case AUDIO_FORMAT_DTS:
Ben Romberger1aaaf862017-04-06 17:49:46 -0700432 case AUDIO_FORMAT_DTS_HD:
Naresh Tanniru928f0862017-04-07 16:44:23 -0700433 case AUDIO_FORMAT_DOLBY_TRUEHD:
434 case AUDIO_FORMAT_IEC61937: {
Harsh Bansal28718c52017-04-20 13:47:12 +0530435 is_enabled = true;
436 break;
437 }
438 default:
439 is_enabled = false;
440 break;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530441 }
442 }
443 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530444
445 return is_enabled;
446}
447
448/*Closes all pcm hdmi output from QAF. */
449static void close_all_pcm_hdmi_output()
450{
451 int i;
452 //Closing all the PCM HDMI output stream from QAF.
453 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
454 if (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]) {
455 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
456 (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]));
457 p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
458 }
459
460 if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
461 && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
462 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
463 (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
464 p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
465 }
466 }
467
468 p_qaf->mch_pcm_hdmi_enabled = 0;
469}
470
471static void close_all_hdmi_output()
472{
473 int k;
474 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
475 if (p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
476 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
477 (struct audio_stream_out *)(p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
478 p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
479 }
480 }
481 p_qaf->passthrough_enabled = 0;
482
483 close_all_pcm_hdmi_output();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530484}
485
486static int qaf_out_callback(stream_callback_event_t event, void *param __unused, void *cookie)
487{
488 struct stream_out *out = (struct stream_out *)cookie;
489
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800490 out->client_callback(event, NULL, out->client_cookie);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530491 return 0;
492}
493
Harsh Bansal28718c52017-04-20 13:47:12 +0530494/* Creates the QAF passthrough output stream. */
495static int create_qaf_passthrough_stream()
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530496{
Harsh Bansal28718c52017-04-20 13:47:12 +0530497 DEBUG_MSG();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530498
Harsh Bansal28718c52017-04-20 13:47:12 +0530499 int ret = 0, k;
500 struct stream_out *out = p_qaf->passthrough_in;
501
502 if (!out) return -EINVAL;
503
504 pthread_mutex_lock(&p_qaf->lock);
505 lock_output_stream(out);
506
507 //Creating QAF passthrough output stream.
508 if (NULL == p_qaf->passthrough_out) {
509 audio_output_flags_t flags;
510 struct audio_config config;
511 audio_devices_t devices;
512
513 config.sample_rate = config.offload_info.sample_rate = out->sample_rate;
514 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
515 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
516 config.offload_info.format = out->format;
517 config.offload_info.bit_width = out->bit_width;
518 config.format = out->format;
519 config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
520
521 //Device is copied from the QAF passthrough input stream.
522 devices = out->devices;
523 flags = out->flags;
524
525 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
526 QAF_DEFAULT_PASSTHROUGH_HANDLE,
527 devices,
528 flags,
529 &config,
530 (struct audio_stream_out **)&(p_qaf->passthrough_out),
531 NULL);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530532 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530533 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
534 unlock_output_stream(out);
535 return ret;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530536 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530537 p_qaf->passthrough_in = out;
538 p_qaf->passthrough_out->stream.set_callback((struct audio_stream_out *)p_qaf->passthrough_out,
539 (stream_callback_t) qaf_out_callback, out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530540 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530541
542 unlock_output_stream(out);
543
544 //Since QAF-Passthrough is created, close other HDMI outputs.
545 close_all_hdmi_output();
546
547 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530548 return ret;
549}
550
Harsh Bansal28718c52017-04-20 13:47:12 +0530551/* Closes the QAF passthrough output stream. */
552static void close_qaf_passthrough_stream()
553{
554 if (p_qaf->passthrough_out != NULL) { //QAF pasthroug is enabled. Close it.
555 pthread_mutex_lock(&p_qaf->lock);
556 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
557 (struct audio_stream_out *)(p_qaf->passthrough_out));
558 p_qaf->passthrough_out = NULL;
559 pthread_mutex_unlock(&p_qaf->lock);
560
561 if (p_qaf->passthrough_in->qaf_stream_handle) {
562 qaf_out_pause((struct audio_stream_out*)p_qaf->passthrough_in);
563 qaf_out_flush((struct audio_stream_out*)p_qaf->passthrough_in);
564 qaf_out_drain((struct audio_stream_out*)p_qaf->passthrough_in,
565 (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
566 }
567 }
568}
569
570/* Sends a command to output stream offload thread. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530571static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
572{
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530573 DEBUG_MSG_VV("command is %d", command);
Harsh Bansal28718c52017-04-20 13:47:12 +0530574
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530575 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
576
577 if (!cmd) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530578 ERROR_MSG("failed to allocate mem for command 0x%x", command);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530579 return -ENOMEM;
580 }
581
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530582 cmd->cmd = command;
Harsh Bansal28718c52017-04-20 13:47:12 +0530583
584 lock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530585 list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
586 pthread_cond_signal(&out->qaf_offload_cond);
Harsh Bansal28718c52017-04-20 13:47:12 +0530587 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530588 return 0;
589}
590
Harsh Bansal28718c52017-04-20 13:47:12 +0530591/* Stops a QAF module stream.*/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530592static int audio_extn_qaf_stream_stop(struct stream_out *out)
593{
Harsh Bansal28718c52017-04-20 13:47:12 +0530594 int ret = 0;
595 DEBUG_MSG("Output Stream 0x%x", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530596
Harsh Bansal9a376832017-06-08 20:18:06 +0530597 if (!check_stream_state(out, RUN)) return ret;
598
Harsh Bansal28718c52017-04-20 13:47:12 +0530599 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
600 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_stop)) {
601 return ret;
602 }
603
604 if (out->qaf_stream_handle) {
605 ret = qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
606 }
607
608 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530609}
610
Harsh Bansal28718c52017-04-20 13:47:12 +0530611/* Puts a QAF module stream in standby. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530612static int qaf_out_standby(struct audio_stream *stream)
613{
614 struct stream_out *out = (struct stream_out *)stream;
615 int status = 0;
616
617 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
618 stream, out->usecase, use_case_table[out->usecase]);
619
620 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +0530621
622 //If QAF passthrough is active then block standby on all the input streams of QAF mm modules.
623 if (p_qaf->passthrough_out) {
624 //If standby is received on QAF passthrough stream then forward it to primary HAL.
625 if (p_qaf->passthrough_in == out) {
626 status = p_qaf->passthrough_out->stream.common.standby(
627 (struct audio_stream *)p_qaf->passthrough_out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530628 }
Harsh Bansal9a376832017-06-08 20:18:06 +0530629 } else if (check_stream_state(out, RUN)) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530630 //If QAF passthrough stream is not active then stop the QAF module stream.
631 status = audio_extn_qaf_stream_stop(out);
Harsh Bansal9a376832017-06-08 20:18:06 +0530632
633 if (status == 0) {
634 //Setting state to stopped as client not expecting drain_ready event.
635 set_stream_state(out, STOPPED);
636 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530637 }
638
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530639 if (!out->standby) {
640 out->standby = true;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530641 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530642
643 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530644 return status;
645}
646
Harsh Bansal28718c52017-04-20 13:47:12 +0530647/* Sets the volume to PCM output stream. */
648static int qaf_out_set_volume(struct audio_stream_out *stream, float left, float right)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530649{
650 int ret = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530651 struct stream_out *out = (struct stream_out *)stream;
652 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530653
Harsh Bansal28718c52017-04-20 13:47:12 +0530654 DEBUG_MSG("Left %f, Right %f", left, right);
655
656 qaf_mod = get_qaf_module_for_input_stream(out);
657 if (!qaf_mod) {
658 return -EINVAL;
659 }
660
661 pthread_mutex_lock(&p_qaf->lock);
662 qaf_mod->vol_left = left;
663 qaf_mod->vol_right = right;
664 qaf_mod->is_vol_set = true;
665 pthread_mutex_unlock(&p_qaf->lock);
666
667 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL) {
668 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
669 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], left, right);
670 }
671
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530672 return ret;
673}
674
Harsh Bansal28718c52017-04-20 13:47:12 +0530675/* Starts a QAF module stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530676static int qaf_stream_start(struct stream_out *out)
677{
Harsh Bansal28718c52017-04-20 13:47:12 +0530678 int ret = -EINVAL;
679 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530680
Harsh Bansal28718c52017-04-20 13:47:12 +0530681 DEBUG_MSG("Output Stream = %p", out);
682
683 qaf_mod = get_qaf_module_for_input_stream(out);
684 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_start)) {
685 return -EINVAL;
686 }
687
688 if (out->qaf_stream_handle) {
689 ret = qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
690 }
691
692 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530693}
694
695static int qaf_start_output_stream(struct stream_out *out)
696{
697 int ret = 0;
698 struct audio_device *adev = out->dev;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530699
700 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
701 ret = -EINVAL;
702 usleep(50000);
703 return ret;
704 }
705
706 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
707 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
708 out->devices);
709
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530710 if (CARD_STATUS_OFFLINE == out->card_status ||
711 CARD_STATUS_OFFLINE == adev->card_status) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530712 ALOGE("%s: sound card is not active/SSR returning error", __func__);
713 ret = -EIO;
714 usleep(50000);
715 return ret;
716 }
717
718 return qaf_stream_start(out);
719}
720
Harsh Bansal28718c52017-04-20 13:47:12 +0530721/* Sends input buffer to the QAF MM module. */
722static int qaf_module_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
723{
724 int ret = -EINVAL;
725 struct qaf_module *qaf_mod = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +0530726
727 qaf_mod = get_qaf_module_for_input_stream(out);
728 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_write)) {
729 return ret;
730 }
731
Harsh Bansal0345a202017-08-31 18:42:18 +0530732 //If data received on associated stream when all other stream are stopped then drop the data.
733 if (out == qaf_mod->stream_in[QAF_IN_ASSOC] && !is_any_stream_running(qaf_mod))
734 return bytes;
735
Harsh Bansal28718c52017-04-20 13:47:12 +0530736 if (out->qaf_stream_handle) {
737 ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
Harsh Bansal9a376832017-06-08 20:18:06 +0530738 if(ret > 0) set_stream_state(out, RUN);
Harsh Bansal28718c52017-04-20 13:47:12 +0530739 }
740 return ret;
741}
742
743/* Writes buffer to QAF input stream. */
744static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530745{
746 struct stream_out *out = (struct stream_out *)stream;
747 struct audio_device *adev = out->dev;
748 ssize_t ret = 0;
749
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530750 DEBUG_MSG_VV("bytes = %d, usecase[%d] and flags[%x] for handle[%p]",
Harsh Bansal28718c52017-04-20 13:47:12 +0530751 (int)bytes, out->usecase, out->flags, out);
752
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530753 lock_output_stream(out);
754
Harsh Bansal28718c52017-04-20 13:47:12 +0530755 // If QAF passthrough is active then block writing data to QAF mm module.
756 if (p_qaf->passthrough_out) {
757 //If write is received for the QAF passthrough stream then send the buffer to primary HAL.
758 if (p_qaf->passthrough_in == out) {
759 ret = p_qaf->passthrough_out->stream.write(
760 (struct audio_stream_out *)(p_qaf->passthrough_out),
761 buffer,
762 bytes);
763 if (ret > 0) out->standby = false;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530764 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530765 unlock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530766 return ret;
Harsh Bansal28718c52017-04-20 13:47:12 +0530767 } else if (out->standby) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530768 pthread_mutex_lock(&adev->lock);
769 ret = qaf_start_output_stream(out);
770 pthread_mutex_unlock(&adev->lock);
Harsh Bansal28718c52017-04-20 13:47:12 +0530771 if (ret == 0) {
772 out->standby = false;
773 } else {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530774 goto exit;
775 }
776 }
777
Harsh Bansal28718c52017-04-20 13:47:12 +0530778 if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530779 audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
780 adev->is_channel_status_set = true;
781 }
782
Harsh Bansal28718c52017-04-20 13:47:12 +0530783 ret = qaf_module_write_input_buffer(out, buffer, bytes);
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530784 DEBUG_MSG_VV("ret [%d]", (int)ret);
Harsh Bansal28718c52017-04-20 13:47:12 +0530785
786 if (ret >= 0) {
Harsh Bansal7c09d5d2017-08-04 14:20:37 +0530787 out->written += ret / ((popcount(out->channel_mask) * sizeof(short)));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530788 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530789
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530790
791exit:
Harsh Bansal28718c52017-04-20 13:47:12 +0530792 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530793
794 if (ret < 0) {
795 if (ret == -EAGAIN) {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530796 DEBUG_MSG_VV("No space available in mm module, post msg to cb thread");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530797 ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530798 bytes = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530799 } else if (ret == -ENOMEM || ret == -EPERM) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530800 if (out->pcm)
Harsh Bansal28718c52017-04-20 13:47:12 +0530801 ERROR_MSG("error %d, %s", (int)ret, pcm_get_error(out->pcm));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530802 qaf_out_standby(&out->stream.common);
Harsh Bansal28718c52017-04-20 13:47:12 +0530803 usleep(bytes * 1000000
804 / audio_stream_out_frame_size(stream)
805 / out->stream.common.get_sample_rate(&out->stream.common));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530806 }
Harsh Bansal7c09d5d2017-08-04 14:20:37 +0530807 } else if (ret < bytes) {
808 //partial buffer copied to the module.
809 DEBUG_MSG_VV("Not enough space available in mm module, post msg to cb thread");
810 (void)qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
811 bytes = ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530812 }
813 return bytes;
814}
815
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530816/* Gets PCM offload buffer size for a given config. */
817static uint32_t qaf_get_pcm_offload_buffer_size(audio_offload_info_t* info,
818 uint32_t samples_per_frame)
Varun B34da7a42017-02-13 16:16:53 +0530819{
820 uint32_t fragment_size = 0;
Varun B34da7a42017-02-13 16:16:53 +0530821
Harsh Bansal28718c52017-04-20 13:47:12 +0530822 fragment_size = (samples_per_frame * (info->bit_width >> 3) * popcount(info->channel_mask));
823
824 if (fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
Varun B34da7a42017-02-13 16:16:53 +0530825 fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
Harsh Bansal28718c52017-04-20 13:47:12 +0530826 else if (fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
Varun B34da7a42017-02-13 16:16:53 +0530827 fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
Harsh Bansal28718c52017-04-20 13:47:12 +0530828
Varun B34da7a42017-02-13 16:16:53 +0530829 // To have same PCM samples for all channels, the buffer size requires to
830 // be multiple of (number of channels * bytes per sample)
831 // For writes to succeed, the buffer must be written at address which is multiple of 32
Harsh Bansal28718c52017-04-20 13:47:12 +0530832 fragment_size = ALIGN(fragment_size,
833 ((info->bit_width >> 3) * popcount(info->channel_mask) * 32));
Varun B34da7a42017-02-13 16:16:53 +0530834
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530835 ALOGI("Qaf PCM offload Fragment size is %d bytes", fragment_size);
Varun B34da7a42017-02-13 16:16:53 +0530836
837 return fragment_size;
838}
839
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +0530840static uint32_t qaf_get_pcm_offload_input_buffer_size(info)
841{
842 return qaf_get_pcm_offload_buffer_size(info, MS12_PCM_IN_FRAGMENT_SIZE);
843}
844
845static uint32_t qaf_get_pcm_offload_output_buffer_size(struct qaf_module *qaf_mod,
846 audio_offload_info_t* info)
847{
848 return qaf_get_pcm_offload_buffer_size(info, get_pcm_output_buffer_size_samples(qaf_mod));
849}
850
Harsh Bansal28718c52017-04-20 13:47:12 +0530851/* Gets buffer latency in samples. */
852static int get_buffer_latency(struct stream_out *out, uint32_t buffer_size, uint32_t *latency)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530853{
Harsh Bansal28718c52017-04-20 13:47:12 +0530854 unsigned long int samples_in_one_encoded_frame;
855 unsigned long int size_of_one_encoded_frame;
856
857 switch (out->format) {
858 case AUDIO_FORMAT_AC3:
859 samples_in_one_encoded_frame = DD_FRAME_SIZE;
860 size_of_one_encoded_frame = DD_ENCODER_OUTPUT_SIZE;
861 break;
862 case AUDIO_FORMAT_E_AC3:
863 samples_in_one_encoded_frame = DDP_FRAME_SIZE;
864 size_of_one_encoded_frame = DDP_ENCODER_OUTPUT_SIZE;
865 break;
866 case AUDIO_FORMAT_DTS:
867 samples_in_one_encoded_frame = DTS_FRAME_SIZE;
868 size_of_one_encoded_frame = DTS_ENCODER_OUTPUT_SIZE;
869 break;
870 case AUDIO_FORMAT_DTS_HD:
871 samples_in_one_encoded_frame = DTSHD_FRAME_SIZE;
872 size_of_one_encoded_frame = DTSHD_ENCODER_OUTPUT_SIZE;
873 break;
874 case AUDIO_FORMAT_PCM_16_BIT:
875 samples_in_one_encoded_frame = 1;
876 size_of_one_encoded_frame = ((out->bit_width) >> 3) * popcount(out->channel_mask);
877 break;
878 default:
879 *latency = 0;
880 return (-EINVAL);
881 }
882
883 *latency = ((buffer_size * samples_in_one_encoded_frame) / size_of_one_encoded_frame);
884 return 0;
885}
886
887/* Returns the number of frames rendered to outside observer. */
888static int qaf_get_rendered_frames(struct stream_out *out, uint64_t *frames)
889{
890 int ret = 0, i;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530891 struct str_parms *parms;
892 int value = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530893 int module_latency = 0;
894 uint32_t kernel_latency = 0;
895 uint32_t dsp_latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530896 int signed_frames = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530897 char* kvpairs = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +0530898 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530899
Harsh Bansal28718c52017-04-20 13:47:12 +0530900 DEBUG_MSG("Output Format %d", out->format);
901
902 qaf_mod = get_qaf_module_for_input_stream(out);
903 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_get_param)) {
904 return -EINVAL;
905 }
906
907 //Get MM module latency.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530908 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "get_latency");
909 if (kvpairs) {
910 parms = str_parms_create_str(kvpairs);
Harsh Bansal28718c52017-04-20 13:47:12 +0530911 ret = str_parms_get_int(parms, "get_latency", &module_latency);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530912 if (ret >= 0) {
913 str_parms_destroy(parms);
914 parms = NULL;
915 }
916 free(kvpairs);
917 kvpairs = NULL;
918 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530919
920 //Get kernel Latency
921 for (i = MAX_QAF_MODULE_OUT - 1; i >= 0; i--) {
922 if (qaf_mod->stream_out[i] == NULL) {
923 continue;
924 } else {
925 unsigned int num_fragments = qaf_mod->stream_out[i]->compr_config.fragments;
926 uint32_t fragment_size = qaf_mod->stream_out[i]->compr_config.fragment_size;
927 uint32_t kernel_buffer_size = num_fragments * fragment_size;
928 get_buffer_latency(qaf_mod->stream_out[i], kernel_buffer_size, &kernel_latency);
929 break;
930 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530931 }
932
Harsh Bansal28718c52017-04-20 13:47:12 +0530933 //Get DSP latency
934 if ((qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL)
935 || (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] != NULL)) {
936 unsigned int sample_rate = 0;
937
938 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
939 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
940 else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
941 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
942
943 audio_usecase_t platform_latency =
944 platform_render_latency(qaf_mod->stream_out[QAF_OUT_OFFLOAD]->usecase);
945 dsp_latency = (platform_latency * sample_rate) / 1000000LL;
946 } else if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL) {
947 unsigned int sample_rate = 0;
948
949 sample_rate = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate; //TODO: How this sample rate can be used?
950 dsp_latency = (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * sample_rate) / 1000;
951 }
952
953 // MM Module Latency + Kernel Latency + DSP Latency
954 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
955 out->platform_latency = module_latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
956 } else {
957 out->platform_latency = (uint32_t)module_latency + kernel_latency + dsp_latency;
958 }
959
960 if (out->format & AUDIO_FORMAT_PCM_16_BIT) {
961 *frames = 0;
962 signed_frames = out->written - out->platform_latency;
963 // It would be unusual for this value to be negative, but check just in case ...
964 if (signed_frames >= 0) {
965 *frames = signed_frames;
966 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530967 } else if (qaf_mod->qaf_audio_stream_get_param) {
968 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
969 if (kvpairs) {
970 parms = str_parms_create_str(kvpairs);
971 ret = str_parms_get_int(parms, "position", &value);
972 if (ret >= 0) {
973 *frames = value;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530974 signed_frames = value - out->platform_latency;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530975 // It would be unusual for this value to be negative, but check just in case ...
976 if (signed_frames >= 0) {
977 *frames = signed_frames;
978 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530979 }
980 str_parms_destroy(parms);
981 }
982 } else {
983 ret = -EINVAL;
984 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530985
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530986 return ret;
987}
988
989static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
Harsh Bansal28718c52017-04-20 13:47:12 +0530990 uint64_t *frames,
991 struct timespec *timestamp)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530992{
993 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +0530994 int ret = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530995
Harsh Bansal28718c52017-04-20 13:47:12 +0530996 DEBUG_MSG("Output Stream %p", stream);
997
998 //If QAF passthorugh output stream is active.
999 if (p_qaf->passthrough_out) {
1000 if (p_qaf->passthrough_in == out) {
1001 //If api is called for QAF passthorugh stream then call the primary HAL api to get the position.
1002 pthread_mutex_lock(&p_qaf->lock);
1003 ret = p_qaf->passthrough_out->stream.get_presentation_position(
1004 (struct audio_stream_out *)p_qaf->passthrough_out,
1005 frames,
1006 timestamp);
1007 pthread_mutex_unlock(&p_qaf->lock);
1008 } else {
1009 //If api is called for other stream then return zero frames.
1010 *frames = 0;
1011 clock_gettime(CLOCK_MONOTONIC, timestamp);
1012 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301013 return ret;
1014 }
1015
Harsh Bansal28718c52017-04-20 13:47:12 +05301016 ret = qaf_get_rendered_frames(out, frames);
1017 clock_gettime(CLOCK_MONOTONIC, timestamp);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301018
1019 return ret;
1020}
1021
Harsh Bansal28718c52017-04-20 13:47:12 +05301022/* Pause the QAF module input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301023static int qaf_stream_pause(struct stream_out *out)
1024{
Harsh Bansal28718c52017-04-20 13:47:12 +05301025 struct qaf_module *qaf_mod = NULL;
1026 int ret = -EINVAL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301027
Harsh Bansal28718c52017-04-20 13:47:12 +05301028 qaf_mod = get_qaf_module_for_input_stream(out);
1029 if (!qaf_mod || !qaf_mod->qaf_audio_stream_pause) {
1030 return -EINVAL;
1031 }
1032
1033 if (out->qaf_stream_handle)
1034 ret = qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
1035
1036 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301037}
1038
Harsh Bansal28718c52017-04-20 13:47:12 +05301039/* Pause a QAF input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301040static int qaf_out_pause(struct audio_stream_out* stream)
1041{
1042 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05301043 int status = 0;
1044 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301045
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301046 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301047
1048 //If QAF passthrough is enabled then block the pause on module stream.
1049 if (p_qaf->passthrough_out) {
1050 pthread_mutex_lock(&p_qaf->lock);
1051 //If pause is received for QAF passthorugh stream then call the primary HAL api.
1052 if (p_qaf->passthrough_in == out) {
1053 status = p_qaf->passthrough_out->stream.pause(
1054 (struct audio_stream_out *)p_qaf->passthrough_out);
1055 out->offload_state = OFFLOAD_STATE_PAUSED;
1056 }
1057 pthread_mutex_unlock(&p_qaf->lock);
1058 } else {
1059 //Pause the module input stream.
1060 status = qaf_stream_pause(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301061 }
1062
Harsh Bansal28718c52017-04-20 13:47:12 +05301063 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301064 return status;
1065}
1066
Harsh Bansal28718c52017-04-20 13:47:12 +05301067/* Drains a qaf input stream. */
1068static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301069{
1070 struct stream_out *out = (struct stream_out *)stream;
1071 int status = 0;
Harsh Bansal0345a202017-08-31 18:42:18 +05301072 struct qaf_module *qaf_mod = NULL;
1073
1074 qaf_mod = get_qaf_module_for_input_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301075 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301076
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301077 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301078
1079 //If QAF passthrough is enabled then block the drain on module stream.
1080 if (p_qaf->passthrough_out) {
1081 pthread_mutex_lock(&p_qaf->lock);
1082 //If drain is received for QAF passthorugh stream then call the primary HAL api.
1083 if (p_qaf->passthrough_in == out) {
1084 status = p_qaf->passthrough_out->stream.drain(
1085 (struct audio_stream_out *)p_qaf->passthrough_out, type);
1086 }
1087 pthread_mutex_unlock(&p_qaf->lock);
Harsh Bansal0345a202017-08-31 18:42:18 +05301088 } else if (!is_any_stream_running(qaf_mod)) {
Harsh Bansal9a376832017-06-08 20:18:06 +05301089 //If stream is already stopped then send the drain ready.
1090 out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
Harsh Bansal0345a202017-08-31 18:42:18 +05301091 set_stream_state(out, STOPPED);
Harsh Bansal28718c52017-04-20 13:47:12 +05301092 } else {
1093 //Drain the module input stream.
1094 /* Stream stop will trigger EOS and on EOS_EVENT received
1095 from callback DRAIN_READY command is sent */
1096 status = audio_extn_qaf_stream_stop(out);
1097
1098 if (status == 0) {
Harsh Bansal9a376832017-06-08 20:18:06 +05301099 //Setting state to stopping as client is expecting drain_ready event.
1100 set_stream_state(out, STOPPING);
Harsh Bansal28718c52017-04-20 13:47:12 +05301101 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301102 }
1103
Harsh Bansal28718c52017-04-20 13:47:12 +05301104 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301105 return status;
1106}
1107
Harsh Bansal28718c52017-04-20 13:47:12 +05301108/* Flush the QAF module input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301109static int audio_extn_qaf_stream_flush(struct stream_out *out)
1110{
Harsh Bansal28718c52017-04-20 13:47:12 +05301111 DEBUG_MSG("Output Stream %p", out);
1112 int ret = -EINVAL;
1113 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301114
Harsh Bansal28718c52017-04-20 13:47:12 +05301115 qaf_mod = get_qaf_module_for_input_stream(out);
1116 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_flush)) {
1117 return -EINVAL;
1118 }
1119
1120 if (out->qaf_stream_handle)
1121 ret = qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
1122
1123 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301124}
1125
Harsh Bansal28718c52017-04-20 13:47:12 +05301126/* Flush the QAF input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301127static int qaf_out_flush(struct audio_stream_out* stream)
1128{
1129 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05301130 int status = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301131
Harsh Bansal28718c52017-04-20 13:47:12 +05301132 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301133 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301134
1135 //If QAF passthrough is active then block the flush on module input streams.
1136 if (p_qaf->passthrough_out) {
1137 pthread_mutex_lock(&p_qaf->lock);
1138 //If flush is received for the QAF passthrough stream then call the primary HAL api.
1139 if (p_qaf->passthrough_in == out) {
1140 status = p_qaf->passthrough_out->stream.flush(
1141 (struct audio_stream_out *)p_qaf->passthrough_out);
1142 out->offload_state = OFFLOAD_STATE_IDLE;
1143 }
1144 pthread_mutex_unlock(&p_qaf->lock);
1145 } else {
1146 //Flush the module input stream.
1147 status = audio_extn_qaf_stream_flush(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301148 }
1149
Harsh Bansal28718c52017-04-20 13:47:12 +05301150 unlock_output_stream(out);
1151 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301152 return status;
1153}
1154
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301155static uint32_t qaf_out_get_latency(const struct audio_stream_out *stream)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301156{
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301157 struct stream_out *out = (struct stream_out *)stream;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301158 uint32_t latency = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +05301159 struct qaf_module *qaf_mod = NULL;
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301160 DEBUG_MSG_VV("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301161
Harsh Bansal28718c52017-04-20 13:47:12 +05301162 qaf_mod = get_qaf_module_for_input_stream(out);
1163 if (!qaf_mod) {
1164 return 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301165 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301166
Harsh Bansal28718c52017-04-20 13:47:12 +05301167 //If QAF passthrough is active then block the get latency on module input streams.
1168 if (p_qaf->passthrough_out) {
1169 pthread_mutex_lock(&p_qaf->lock);
1170 //If get latency is called for the QAF passthrough stream then call the primary HAL api.
1171 if (p_qaf->passthrough_in == out) {
1172 latency = p_qaf->passthrough_out->stream.get_latency(
1173 (struct audio_stream_out *)p_qaf->passthrough_out);
1174 }
1175 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301176 } else {
Bharath Gopal01310bb2016-12-05 15:39:32 +05301177 if (is_offload_usecase(out->usecase)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301178 latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301179 } else {
Harsh Bansal28718c52017-04-20 13:47:12 +05301180 uint32_t sample_rate = 0;
1181 latency = QAF_MODULE_PCM_INPUT_BUFFER_LATENCY; //Input latency
1182
1183 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
1184 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
1185 else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
1186 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
1187
1188 if (sample_rate) {
1189 latency += (get_pcm_output_buffer_size_samples(qaf_mod) * 1000) / out->sample_rate;
1190 }
1191 }
1192
1193 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
1194 if (is_offload_usecase(out->usecase)) {
1195 latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
1196 QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
1197 } else {
1198 latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
1199 QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
1200 }
Bharath Gopal01310bb2016-12-05 15:39:32 +05301201 }
1202 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301203
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301204 DEBUG_MSG_VV("Latency %d", latency);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301205 return latency;
1206}
1207
Harsh Bansal28718c52017-04-20 13:47:12 +05301208static bool check_and_get_compressed_device_format(int device, int *format)
1209{
1210 switch (device) {
1211 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD):
1212 *format = AUDIO_FORMAT_AC3;
1213 return true;
1214 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP):
1215 *format = AUDIO_FORMAT_E_AC3;
1216 return true;
1217 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS):
1218 *format = AUDIO_FORMAT_DTS;
1219 return true;
Harsh Bansal28718c52017-04-20 13:47:12 +05301220 default:
1221 return false;
1222 }
1223}
1224
Harsh Bansal9a376832017-06-08 20:18:06 +05301225static void set_out_stream_channel_map(struct stream_out *out, audio_qaf_media_format_t *media_fmt)
1226{
1227 if (media_fmt == NULL || out == NULL) {
1228 return;
1229 }
1230 struct audio_out_channel_map_param chmap = {0};
1231 int i = 0;
1232 chmap.channels = media_fmt->channels;
1233 for (i = 0; i < chmap.channels && i < AUDIO_CHANNEL_COUNT_MAX && i < AUDIO_QAF_MAX_CHANNELS;
1234 i++) {
1235 chmap.channel_map[i] = media_fmt->ch_map[i];
1236 }
1237 audio_extn_utils_set_channel_map(out, &chmap);
1238}
1239
Harsh Bansal28718c52017-04-20 13:47:12 +05301240/* Call back function for mm module. */
1241static void notify_event_callback(audio_session_handle_t session_handle /*__unused*/,
1242 void *prv_data,
1243 void *buf,
1244 audio_event_id_t event_id,
1245 int size,
1246 int device) //TODO: add media format as well.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301247{
1248
Harsh Bansal28718c52017-04-20 13:47:12 +05301249 /*
1250 For SPKR:
1251 1. Open pcm device if device_id passed to it SPKR and write the data to
1252 pcm device
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301253
Harsh Bansal28718c52017-04-20 13:47:12 +05301254 For HDMI
1255 1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format and write
1256 data to the HDMI device.
1257 */
1258 int ret, i;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301259 audio_output_flags_t flags;
Harsh Bansal28718c52017-04-20 13:47:12 +05301260 struct qaf_module* qaf_mod = (struct qaf_module*)prv_data;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301261 struct audio_stream_out *bt_stream = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301262 int format;
Harsh Bansal431eede2017-04-28 21:22:30 +05301263 int8_t *data_buffer_p = NULL;
1264 uint32_t buffer_size = 0;
1265 bool need_to_recreate_stream = false;
1266 struct audio_config config;
Harsh Bansal9a376832017-06-08 20:18:06 +05301267 audio_qaf_media_format_t *media_fmt = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301268
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301269 DEBUG_MSG_VV("Device 0x%X, Event = 0x%X, Bytes to write %d", device, event_id, size);
Harsh Bansal0345a202017-08-31 18:42:18 +05301270
1271
Harsh Bansal28718c52017-04-20 13:47:12 +05301272 pthread_mutex_lock(&p_qaf->lock);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301273
Harsh Bansal431eede2017-04-28 21:22:30 +05301274 /* Default config initialization. */
1275 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
1276 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1277 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
1278 config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
1279 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
1280 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
1281
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001282 if (event_id == AUDIO_SEC_FAIL_EVENT) {
1283 DEBUG_MSG("%s Security failed, closing session");
1284 qaf_session_close(qaf_mod);
1285 pthread_mutex_unlock(&p_qaf->lock);
1286 return;
1287 }
1288
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301289 if (event_id == AUDIO_DATA_EVENT) {
Harsh Bansal431eede2017-04-28 21:22:30 +05301290 data_buffer_p = (int8_t*)buf;
1291 buffer_size = size;
1292 } else if (event_id == AUDIO_DATA_EVENT_V2) {
1293 audio_qaf_out_buffer_t *buf_payload = (audio_qaf_out_buffer_t*)buf;
1294 int index = -1;
Harsh Bansal431eede2017-04-28 21:22:30 +05301295
1296 if (size < sizeof(audio_qaf_out_buffer_t)) {
1297 ERROR_MSG("AUDIO_DATA_EVENT_V2 payload size is not sufficient.");
1298 return;
1299 }
1300
1301 data_buffer_p = (int8_t*)buf_payload->data + buf_payload->offset;
1302 buffer_size = buf_payload->size - buf_payload->offset;
1303
1304 index = get_media_fmt_array_index_for_output_id(qaf_mod, buf_payload->output_id);
1305
1306 if (index < 0) {
1307 /*If media format is not received then switch to default values.*/
1308 event_id = AUDIO_DATA_EVENT;
1309 } else {
Harsh Bansal9a376832017-06-08 20:18:06 +05301310 media_fmt = &qaf_mod->out_stream_fmt[index];
Harsh Bansal431eede2017-04-28 21:22:30 +05301311 need_to_recreate_stream = qaf_mod->is_media_fmt_changed[index];
1312 qaf_mod->is_media_fmt_changed[index] = false;
1313
Harsh Bansal9a376832017-06-08 20:18:06 +05301314 config.sample_rate = config.offload_info.sample_rate = media_fmt->sample_rate;
Harsh Bansal431eede2017-04-28 21:22:30 +05301315 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1316 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
Harsh Bansal9a376832017-06-08 20:18:06 +05301317 config.format = config.offload_info.format = media_fmt->format;
1318 config.offload_info.bit_width = media_fmt->bit_width;
Harsh Bansal431eede2017-04-28 21:22:30 +05301319
Harsh Bansal9a376832017-06-08 20:18:06 +05301320 if (media_fmt->format == AUDIO_FORMAT_PCM) {
1321 if (media_fmt->bit_width == 16)
Harsh Bansal431eede2017-04-28 21:22:30 +05301322 config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
Harsh Bansal9a376832017-06-08 20:18:06 +05301323 else if (media_fmt->bit_width == 24)
Harsh Bansal431eede2017-04-28 21:22:30 +05301324 config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
1325 else
1326 config.format = config.offload_info.format = AUDIO_FORMAT_PCM_32_BIT;
1327 }
1328
Harsh Bansal9a376832017-06-08 20:18:06 +05301329 device |= (media_fmt->format & AUDIO_FORMAT_MAIN_MASK);
Harsh Bansal431eede2017-04-28 21:22:30 +05301330
Harsh Bansal9a376832017-06-08 20:18:06 +05301331 config.channel_mask = audio_channel_out_mask_from_count(media_fmt->channels);
1332 config.offload_info.channel_mask = config.channel_mask;
Harsh Bansal431eede2017-04-28 21:22:30 +05301333 }
1334 }
1335
1336 if (event_id == AUDIO_OUTPUT_MEDIA_FORMAT_EVENT) {
1337 audio_qaf_media_format_t *p_fmt = (audio_qaf_media_format_t*)buf;
1338 audio_qaf_media_format_t *p_cached_fmt = NULL;
1339 int index = -1;
1340
1341 if (size < sizeof(audio_qaf_media_format_t)) {
1342 ERROR_MSG("Size is not proper for the event AUDIO_OUTPUT_MEDIA_FORMAT_EVENT.");
1343 return ;
1344 }
1345
1346 index = get_media_fmt_array_index_for_output_id(qaf_mod, p_fmt->output_id);
1347
1348 if (index >= 0) {
1349 p_cached_fmt = &qaf_mod->out_stream_fmt[index];
1350 } else if (index < 0 && qaf_mod->new_out_format_index < MAX_QAF_MODULE_OUT) {
1351 index = qaf_mod->new_out_format_index;
1352 p_cached_fmt = &qaf_mod->out_stream_fmt[index];
1353 qaf_mod->new_out_format_index++;
1354 }
1355
1356 if (p_cached_fmt == NULL) {
1357 ERROR_MSG("Maximum output from a QAF module is reached. Can not process new output.");
1358 return ;
1359 }
1360
1361 if (memcmp(p_cached_fmt, p_fmt, sizeof(audio_qaf_media_format_t)) != 0) {
1362 memcpy(p_cached_fmt, p_fmt, sizeof(audio_qaf_media_format_t));
1363 qaf_mod->is_media_fmt_changed[index] = true;
1364 }
1365 } else if (event_id == AUDIO_DATA_EVENT || event_id == AUDIO_DATA_EVENT_V2) {
1366
Harsh Bansal28718c52017-04-20 13:47:12 +05301367 if (p_qaf->passthrough_out != NULL) {
1368 //If QAF passthrough is active then all the module output will be dropped.
1369 pthread_mutex_unlock(&p_qaf->lock);
1370 DEBUG_MSG("QAF-PSTH is active, DROPPING DATA!");
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301371 return;
Harsh Bansal28718c52017-04-20 13:47:12 +05301372 }
1373
1374 if (check_and_get_compressed_device_format(device, &format)) {
1375 /*
1376 * CASE 1: Transcoded output of mm module.
1377 * If HDMI is not connected then drop the data.
1378 * Only one HDMI output can be supported from all the mm modules of QAF.
1379 * Multi-Channel PCM HDMI output streams will be closed from all the mm modules.
1380 * If transcoded output of other module is already enabled then this data will be dropped.
1381 */
1382
1383 if (!p_qaf->hdmi_connect) {
1384 DEBUG_MSG("HDMI not connected, DROPPING DATA!");
1385 pthread_mutex_unlock(&p_qaf->lock);
1386 return;
1387 }
1388
1389 //Closing all the PCM HDMI output stream from QAF.
1390 close_all_pcm_hdmi_output();
1391
Harsh Bansal431eede2017-04-28 21:22:30 +05301392 /* If Media format was changed for this stream then need to re-create the stream. */
1393 if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
1394 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1395 (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
1396 qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
1397 p_qaf->passthrough_enabled = false;
1398 }
1399
Harsh Bansal28718c52017-04-20 13:47:12 +05301400 if (!p_qaf->passthrough_enabled
1401 && !(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH])) {
1402
Harsh Bansal28718c52017-04-20 13:47:12 +05301403 audio_devices_t devices;
1404
Harsh Bansal28718c52017-04-20 13:47:12 +05301405 config.format = config.offload_info.format = format;
Harsh Bansal28718c52017-04-20 13:47:12 +05301406 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
1407
1408 flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING
1409 | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
Harsh Bansal6bf3b4d2017-08-24 11:16:13 +05301410 | AUDIO_OUTPUT_FLAG_DIRECT
1411 | AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH);
Harsh Bansal28718c52017-04-20 13:47:12 +05301412 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
1413
1414 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1415 QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE,
1416 devices,
1417 flags,
1418 &config,
1419 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]),
1420 NULL);
1421 if (ret < 0) {
1422 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1423 pthread_mutex_unlock(&p_qaf->lock);
1424 return;
1425 }
1426
Harsh Bansal6bf3b4d2017-08-24 11:16:13 +05301427 if (format == AUDIO_FORMAT_E_AC3) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301428 qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragment_size =
1429 COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE;
1430 }
1431 qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
1432 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1433
1434 p_qaf->passthrough_enabled = true;
1435 }
1436
1437 if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
1438 ret = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
1439 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH],
Harsh Bansal431eede2017-04-28 21:22:30 +05301440 data_buffer_p,
1441 buffer_size);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301442 }
1443 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301444 else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1445 && (p_qaf->hdmi_connect)
1446 && (p_qaf->hdmi_sink_channels > 2)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301447
Harsh Bansal28718c52017-04-20 13:47:12 +05301448 /* CASE 2: Multi-Channel PCM output to HDMI.
1449 * If any other HDMI output is already enabled then this has to be dropped.
1450 */
1451 bool create_mch_out_stream = false;
1452
1453 if (p_qaf->passthrough_enabled) {
1454 //Closing all the multi-Channel PCM HDMI output stream from QAF.
1455 close_all_pcm_hdmi_output();
1456
1457 //If passthrough is active then pcm hdmi output has to be dropped.
1458 pthread_mutex_unlock(&p_qaf->lock);
1459 DEBUG_MSG("Compressed passthrough enabled, DROPPING DATA!");
1460 return;
1461 }
1462
Harsh Bansal431eede2017-04-28 21:22:30 +05301463 /* If Media format was changed for this stream then need to re-create the stream. */
1464 if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
1465 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1466 (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]));
1467 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
1468 p_qaf->mch_pcm_hdmi_enabled = false;
1469 }
1470
Harsh Bansal28718c52017-04-20 13:47:12 +05301471 if (!p_qaf->mch_pcm_hdmi_enabled && !(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301472 audio_devices_t devices;
1473
Harsh Bansal431eede2017-04-28 21:22:30 +05301474 if (event_id == AUDIO_DATA_EVENT) {
1475 config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301476
Harsh Bansal431eede2017-04-28 21:22:30 +05301477 if (p_qaf->hdmi_sink_channels == 8) {
1478 config.offload_info.channel_mask = config.channel_mask =
1479 AUDIO_CHANNEL_OUT_7POINT1;
1480 } else if (p_qaf->hdmi_sink_channels == 6) {
1481 config.offload_info.channel_mask = config.channel_mask =
1482 AUDIO_CHANNEL_OUT_5POINT1;
1483 } else {
1484 config.offload_info.channel_mask = config.channel_mask =
1485 AUDIO_CHANNEL_OUT_STEREO;
1486 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301487 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301488
Harsh Bansal28718c52017-04-20 13:47:12 +05301489 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
1490 flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
1491
1492 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1493 QAF_DEFAULT_COMPR_AUDIO_HANDLE,
1494 devices,
1495 flags,
1496 &config,
1497 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]),
1498 NULL);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301499 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301500 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1501 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301502 return;
1503 }
Harsh Bansal9a376832017-06-08 20:18:06 +05301504 set_out_stream_channel_map(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], media_fmt);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001505
Harsh Bansal28718c52017-04-20 13:47:12 +05301506 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
1507 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1508 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301509 qaf_get_pcm_offload_output_buffer_size(qaf_mod, &config.offload_info);
Harsh Bansal28718c52017-04-20 13:47:12 +05301510
1511 p_qaf->mch_pcm_hdmi_enabled = true;
1512
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301513 if ((qaf_mod->stream_in[QAF_IN_MAIN]
1514 && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) ||
1515 (qaf_mod->stream_in[QAF_IN_MAIN_2]
1516 && qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback != NULL)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301517
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301518 if (qaf_mod->stream_in[QAF_IN_MAIN]) {
1519 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
Harsh Bansal28718c52017-04-20 13:47:12 +05301520 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1521 qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
1522 qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301523 }
1524 if (qaf_mod->stream_in[QAF_IN_MAIN_2]) {
1525 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
1526 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1527 qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback,
1528 qaf_mod->stream_in[QAF_IN_MAIN_2]->client_cookie);
1529 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301530 } else if (qaf_mod->stream_in[QAF_IN_PCM]
1531 && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
1532
1533 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
1534 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1535 qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
1536 qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
1537 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001538
1539 int index = -1;
1540 if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301541 index = (int) QAF_IN_MAIN;
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301542 else if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN_2].adsp_hdlr_config_valid)
1543 index = (int) QAF_IN_MAIN_2;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001544 else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301545 index = (int) QAF_IN_PCM;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001546
Harsh Bansal28718c52017-04-20 13:47:12 +05301547 if (index >= 0) {
1548 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->standby)
1549 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
1550 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
1551
1552 lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001553 ret = audio_extn_out_set_param_data(
Harsh Bansal28718c52017-04-20 13:47:12 +05301554 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1555 AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
1556 (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
1557 unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001558
1559 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301560 }
1561
Harsh Bansal28718c52017-04-20 13:47:12 +05301562 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
1563 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
1564 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
Harsh Bansal431eede2017-04-28 21:22:30 +05301565 data_buffer_p,
1566 buffer_size);
Varun B34da7a42017-02-13 16:16:53 +05301567 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301568 }
1569 else {
1570 /* CASE 3: PCM output.
1571 */
Harsh Bansal431eede2017-04-28 21:22:30 +05301572
1573 /* If Media format was changed for this stream then need to re-create the stream. */
1574 if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
1575 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1576 (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
1577 qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
1578 }
1579
Bharath Gopal01310bb2016-12-05 15:39:32 +05301580 bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
1581 if (bt_stream != NULL) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301582 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
1583 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1584 (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
1585 qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301586 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301587
Harsh Bansal431eede2017-04-28 21:22:30 +05301588 audio_extn_bt_hal_out_write(p_qaf->bt_hdl, data_buffer_p, buffer_size);
Harsh Bansal28718c52017-04-20 13:47:12 +05301589 } else if (NULL == qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301590 audio_devices_t devices;
1591
Harsh Bansal28718c52017-04-20 13:47:12 +05301592 if (qaf_mod->stream_in[QAF_IN_MAIN])
1593 devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
1594 else
1595 devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
1596
1597 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
1598 if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
1599 if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1600 devices ^= AUDIO_DEVICE_OUT_AUX_DIGITAL;
1601 }
1602 if (devices == 0) {
1603 devices = device;
1604 }
1605
1606 flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001607
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301608 /* TODO:: Need to Propagate errors to framework */
Harsh Bansal28718c52017-04-20 13:47:12 +05301609 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1610 QAF_DEFAULT_COMPR_AUDIO_HANDLE,
1611 devices,
1612 flags,
1613 &config,
1614 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_OFFLOAD]),
1615 NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301616 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301617 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1618 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301619 return;
1620 }
Harsh Bansal9a376832017-06-08 20:18:06 +05301621 set_out_stream_channel_map(qaf_mod->stream_out[QAF_OUT_OFFLOAD], media_fmt);
Deepak Agarwal1e42b852017-02-11 17:57:04 +05301622
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301623 if ((qaf_mod->stream_in[QAF_IN_MAIN]
1624 && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) ||
1625 (qaf_mod->stream_in[QAF_IN_MAIN_2]
1626 && qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback != NULL)) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001627
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301628 if (qaf_mod->stream_in[QAF_IN_MAIN]) {
1629 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
Harsh Bansal28718c52017-04-20 13:47:12 +05301630 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1631 qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
1632 qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301633 }
1634 if (qaf_mod->stream_in[QAF_IN_MAIN_2]) {
1635 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
1636 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1637 qaf_mod->stream_in[QAF_IN_MAIN_2]->client_callback,
1638 qaf_mod->stream_in[QAF_IN_MAIN_2]->client_cookie);
1639 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301640 } else if (qaf_mod->stream_in[QAF_IN_PCM]
1641 && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
1642
1643 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
1644 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1645 qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
1646 qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
1647 }
1648
1649 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
1650 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1651 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301652 qaf_get_pcm_offload_output_buffer_size(qaf_mod, &config.offload_info);
Harsh Bansal28718c52017-04-20 13:47:12 +05301653
1654 if (qaf_mod->is_vol_set) {
1655 DEBUG_MSG("Setting Volume Left[%f], Right[%f]", qaf_mod->vol_left, qaf_mod->vol_right);
1656 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
1657 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1658 qaf_mod->vol_left,
1659 qaf_mod->vol_right);
1660 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001661
1662 int index = -1;
1663 if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301664 index = (int) QAF_IN_MAIN;
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301665 else if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN_2].adsp_hdlr_config_valid)
1666 index = (int) QAF_IN_MAIN_2;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001667 else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301668 index = (int) QAF_IN_PCM;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001669 if (index >= 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301670 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]->standby) {
1671 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
1672 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], NULL, 0);
1673 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001674
Harsh Bansal28718c52017-04-20 13:47:12 +05301675 lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001676 ret = audio_extn_out_set_param_data(
Harsh Bansal28718c52017-04-20 13:47:12 +05301677 qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1678 AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
1679 (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
1680 unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301681 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301682 }
1683
1684 /*
1685 * TODO:: Since this is mixed data,
1686 * need to identify to which stream the error should be sent
1687 */
Harsh Bansal28718c52017-04-20 13:47:12 +05301688 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
1689 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
1690 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
Harsh Bansal431eede2017-04-28 21:22:30 +05301691 data_buffer_p,
1692 buffer_size);
Varun B34da7a42017-02-13 16:16:53 +05301693 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301694 }
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301695 DEBUG_MSG_VV("Bytes written = %d", ret);
Harsh Bansal28718c52017-04-20 13:47:12 +05301696 }
Harsh Bansal9381c892017-07-26 15:55:18 +05301697 else if (event_id == AUDIO_EOS_EVENT
1698 || event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301699 || event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
Varun B34da7a42017-02-13 16:16:53 +05301700 || event_id == AUDIO_EOS_MAIN_AAC_EVENT
1701 || event_id == AUDIO_EOS_MAIN_AC4_EVENT
Harsh Bansal0345a202017-08-31 18:42:18 +05301702 || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
1703 || event_id == AUDIO_EOS_ASSOC_AAC_EVENT
1704 || event_id == AUDIO_EOS_ASSOC_AC4_EVENT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301705 struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
Harsh Bansal9381c892017-07-26 15:55:18 +05301706 struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301707 struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
Harsh Bansal28718c52017-04-20 13:47:12 +05301708 struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
Varun B34da7a42017-02-13 16:16:53 +05301709
1710 /**
1711 * TODO:: Only DD/DDP Associate Eos is handled, need to add support
1712 * for other formats.
1713 */
Harsh Bansal9381c892017-07-26 15:55:18 +05301714 if (event_id == AUDIO_EOS_EVENT
1715 && (out_pcm != NULL)
1716 && (check_stream_state(out_pcm, STOPPING))) {
1717
1718 lock_output_stream(out_pcm);
1719 out_pcm->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_pcm->client_cookie);
1720 set_stream_state(out_pcm, STOPPED);
1721 unlock_output_stream(out_pcm);
1722 DEBUG_MSG("sent pcm DRAIN_READY");
Harsh Bansal0345a202017-08-31 18:42:18 +05301723 } else if ( (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
1724 || event_id == AUDIO_EOS_ASSOC_AAC_EVENT
1725 || event_id == AUDIO_EOS_ASSOC_AC4_EVENT)
Harsh Bansal28718c52017-04-20 13:47:12 +05301726 && (out_assoc != NULL)
Harsh Bansal9a376832017-06-08 20:18:06 +05301727 && (check_stream_state(out_assoc, STOPPING))) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301728
Varun B34da7a42017-02-13 16:16:53 +05301729 lock_output_stream(out_assoc);
Harsh Bansal28718c52017-04-20 13:47:12 +05301730 out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_assoc->client_cookie);
Harsh Bansal9a376832017-06-08 20:18:06 +05301731 set_stream_state(out_assoc, STOPPED);
Harsh Bansal28718c52017-04-20 13:47:12 +05301732 unlock_output_stream(out_assoc);
1733 DEBUG_MSG("sent associated DRAIN_READY");
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301734 } else if (event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
1735 && (out_main2 != NULL)
Harsh Bansal9a376832017-06-08 20:18:06 +05301736 && (check_stream_state(out_main2, STOPPING))) {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301737
1738 lock_output_stream(out_main2);
1739 out_main2->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_main2->client_cookie);
Harsh Bansal9a376832017-06-08 20:18:06 +05301740 set_stream_state(out_main2, STOPPED);
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05301741 unlock_output_stream(out_main2);
1742 DEBUG_MSG("sent main2 DRAIN_READY");
Harsh Bansal9a376832017-06-08 20:18:06 +05301743 } else if ((out != NULL) && (check_stream_state(out, STOPPING))) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301744 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001745 out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
Harsh Bansal9a376832017-06-08 20:18:06 +05301746 set_stream_state(out, STOPPED);
Harsh Bansal28718c52017-04-20 13:47:12 +05301747 unlock_output_stream(out);
1748 DEBUG_MSG("sent main DRAIN_READY");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301749 }
1750 }
Harsh Bansal431eede2017-04-28 21:22:30 +05301751 else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301752 struct stream_out *out = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301753
1754 if (event_id == AUDIO_MAIN_EOS_EVENT) {
1755 out = qaf_mod->stream_in[QAF_IN_MAIN];
Harsh Bansal28718c52017-04-20 13:47:12 +05301756 } else {
1757 out = qaf_mod->stream_in[QAF_IN_ASSOC];
Harsh Bansal28718c52017-04-20 13:47:12 +05301758 }
1759
Harsh Bansal9a376832017-06-08 20:18:06 +05301760 if ((out != NULL) && (check_stream_state(out, STOPPING))) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301761 lock_output_stream(out);
1762 out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
Harsh Bansal9a376832017-06-08 20:18:06 +05301763 set_stream_state(out, STOPPED);
Harsh Bansal28718c52017-04-20 13:47:12 +05301764 unlock_output_stream(out);
1765 DEBUG_MSG("sent DRAIN_READY");
1766 }
1767 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301768
1769 pthread_mutex_unlock(&p_qaf->lock);
1770 return;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301771}
1772
Harsh Bansal28718c52017-04-20 13:47:12 +05301773/* Close the mm module session. */
1774static int qaf_session_close(struct qaf_module* qaf_mod)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301775{
Harsh Bansal28718c52017-04-20 13:47:12 +05301776 int j;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301777
Harsh Bansal28718c52017-04-20 13:47:12 +05301778 //Check if all streams are closed or not.
1779 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
1780 if (qaf_mod->stream_in[j] != NULL) {
1781 break;
1782 }
1783 }
1784 if (j != MAX_QAF_MODULE_IN) {
1785 return 0; //Some stream is already active, Can not close session.
1786 }
1787
1788 if (qaf_mod->session_handle != NULL && qaf_mod->qaf_audio_session_close) {
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001789#ifdef AUDIO_EXTN_IP_HDLR_ENABLED
1790 if (qaf_mod == &p_qaf->qaf_mod[MS12]) {
1791 audio_extn_ip_hdlr_intf_close(qaf_mod->ip_hdlr_hdl, false, qaf_mod->session_handle);
1792 }
1793#endif
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301794 qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
1795 qaf_mod->session_handle = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301796 qaf_mod->is_vol_set = false;
Harsh Bansal9a376832017-06-08 20:18:06 +05301797 memset(qaf_mod->stream_state, 0, sizeof(qaf_mod->stream_state));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301798 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301799
1800 for (j = 0; j < MAX_QAF_MODULE_OUT; j++) {
1801 if (qaf_mod->stream_out[j]) {
1802 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1803 (struct audio_stream_out *)(qaf_mod->stream_out[j]));
1804 qaf_mod->stream_out[j] = NULL;
1805 }
Harsh Bansal431eede2017-04-28 21:22:30 +05301806 memset(&qaf_mod->out_stream_fmt[j], 0, sizeof(audio_qaf_media_format_t));
1807 qaf_mod->is_media_fmt_changed[j] = false;
Harsh Bansal28718c52017-04-20 13:47:12 +05301808 }
Harsh Bansal431eede2017-04-28 21:22:30 +05301809 qaf_mod->new_out_format_index = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +05301810
1811 DEBUG_MSG("Session Closed.");
1812
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301813 return 0;
1814}
1815
Harsh Bansal28718c52017-04-20 13:47:12 +05301816/* Close the stream of QAF module. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301817static int qaf_stream_close(struct stream_out *out)
1818{
Harsh Bansal28718c52017-04-20 13:47:12 +05301819 int ret = -EINVAL;
1820 struct qaf_module *qaf_mod = NULL;
1821 int index = -1;
1822 DEBUG_MSG("Flag [0x%x], Stream handle [%p]", out->flags, out->qaf_stream_handle);
1823
1824 qaf_mod = get_qaf_module_for_input_stream(out);
1825 index = get_input_stream_index(out);
1826
1827 if (!qaf_mod || !qaf_mod->qaf_audio_stream_close || index < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301828 return -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301829 }
1830
Harsh Bansal0345a202017-08-31 18:42:18 +05301831 pthread_mutex_lock(&p_qaf->lock);
1832
Harsh Bansal9a376832017-06-08 20:18:06 +05301833 set_stream_state(out,STOPPED);
Harsh Bansal28718c52017-04-20 13:47:12 +05301834 qaf_mod->stream_in[index] = NULL;
1835 memset(&qaf_mod->adsp_hdlr_config[index], 0, sizeof(struct qaf_adsp_hdlr_config_state));
1836
1837 lock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301838 if (out->qaf_stream_handle) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301839 ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
1840 out->qaf_stream_handle = NULL;
1841 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301842 unlock_output_stream(out);
1843
1844 //If all streams are closed then close the session.
1845 qaf_session_close(qaf_mod);
1846
Harsh Bansal0345a202017-08-31 18:42:18 +05301847 pthread_mutex_unlock(&p_qaf->lock);
1848
Harsh Bansal28718c52017-04-20 13:47:12 +05301849 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301850 return ret;
1851}
1852
Harsh Bansal28718c52017-04-20 13:47:12 +05301853/* Open a MM module session with QAF. */
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001854static int audio_extn_qaf_session_open(mm_module_type mod_type, struct stream_out *out)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301855{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301856 ALOGV("%s %d", __func__, __LINE__);
Harsh Bansal28718c52017-04-20 13:47:12 +05301857 unsigned char* license_data = NULL;
1858 device_license_config_t lic_config = {0};
1859 int ret = -ENOSYS, size = 0;
1860 char value[PROPERTY_VALUE_MAX] = {0};
1861 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301862
Harsh Bansal28718c52017-04-20 13:47:12 +05301863 if (mod_type >= MAX_MM_MODULE_TYPE || !(p_qaf->qaf_mod[mod_type].qaf_audio_session_open))
1864 return -ENOTSUP; //Not supported by QAF module.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301865
Harsh Bansal28718c52017-04-20 13:47:12 +05301866 pthread_mutex_lock(&p_qaf->lock);
1867
1868 qaf_mod = &(p_qaf->qaf_mod[mod_type]);
1869
1870 //If session is already opened then return.
1871 if (qaf_mod->session_handle) {
1872 DEBUG_MSG("Session is already opened.");
1873 pthread_mutex_unlock(&p_qaf->lock);
1874 return 0;
1875 }
1876
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001877#ifndef AUDIO_EXTN_IP_HDLR_ENABLED
Harsh Bansal28718c52017-04-20 13:47:12 +05301878 if (mod_type == MS12) {
1879 //Getting the license
1880 license_data = platform_get_license((struct audio_hw_device *)(p_qaf->adev->platform),
1881 &size);
1882 if (!license_data) {
1883 ERROR_MSG("License data is not present.");
1884 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301885 return -EINVAL;
1886 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301887
1888 lic_config.p_license = (unsigned char*)calloc(1, size);
1889 if (lic_config.p_license == NULL) {
1890 ERROR_MSG("Out of Memory");
1891 ret = -ENOMEM;
1892 goto exit;
1893 }
1894
1895 lic_config.l_size = size;
1896 memcpy(lic_config.p_license, license_data, size);
1897
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07001898 if (property_get("vendor.audio.qaf.manufacturer", value, "") && atoi(value)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301899 lic_config.manufacturer_id = (unsigned long)atoi(value);
1900 } else {
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07001901 ERROR_MSG("vendor.audio.qaf.manufacturer id is not set");
Harsh Bansal28718c52017-04-20 13:47:12 +05301902 ret = -EINVAL;
1903 goto exit;
1904 }
1905 }
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001906#endif
Harsh Bansal28718c52017-04-20 13:47:12 +05301907
1908 ret = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
Sri Karri1fbfef52017-06-29 19:45:47 +05301909 AUDIO_SESSION_BROADCAST,
Harsh Bansal28718c52017-04-20 13:47:12 +05301910 (void *)(qaf_mod),
1911 (void *)&lic_config);
1912 if (ret < 0) {
1913 ERROR_MSG("Error in session open %d", ret);
1914 goto exit;
1915 }
1916
1917 if (qaf_mod->session_handle == NULL) {
1918 ERROR_MSG("Session handle is NULL.");
1919 ret = -ENOMEM;
1920 goto exit;
1921 }
1922
1923 if (qaf_mod->qaf_register_event_callback)
1924 qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
1925 qaf_mod,
1926 &notify_event_callback,
Harsh Bansal431eede2017-04-28 21:22:30 +05301927 AUDIO_DATA_EVENT_V2);
Harsh Bansal28718c52017-04-20 13:47:12 +05301928
1929 set_hdmi_configuration_to_module();
1930
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001931#ifdef AUDIO_EXTN_IP_HDLR_ENABLED
1932 if (mod_type == MS12) {
1933 ret = audio_extn_ip_hdlr_intf_open(qaf_mod->ip_hdlr_hdl, false, qaf_mod->session_handle, out->usecase);
1934 if (ret < 0) {
1935 ERROR_MSG("audio_extn_ip_hdlr_intf_open failed, ret = %d", __func__, ret);
1936 goto exit;
1937 }
1938 }
1939#endif
1940
Harsh Bansal28718c52017-04-20 13:47:12 +05301941exit:
1942 if (license_data != NULL) {
1943 free(license_data);
1944 license_data = NULL;
1945 }
1946 if (lic_config.p_license != NULL) {
1947 free(lic_config.p_license);
1948 lic_config.p_license = NULL;
1949 }
1950
1951 pthread_mutex_unlock(&p_qaf->lock);
1952 return ret;
1953}
1954
1955/* opens a stream in QAF module. */
1956static int qaf_stream_open(struct stream_out *out,
1957 struct audio_config *config,
1958 audio_output_flags_t flags,
1959 audio_devices_t devices)
1960{
1961 int status = -EINVAL;
1962 mm_module_type mmtype = get_mm_module_for_format(config->format);
1963 struct qaf_module* qaf_mod = NULL;
1964 DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
1965
Vidyakumar Athotaa00ef462017-08-08 12:52:39 -07001966 if (mmtype >= MAX_MM_MODULE_TYPE) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301967 ERROR_MSG("Unsupported Stream");
1968 return -ENOTSUP;
1969 }
1970
Vidyakumar Athotaa00ef462017-08-08 12:52:39 -07001971 if (p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL ||
1972 p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
1973 ERROR_MSG("Session or Stream is NULL");
1974 return status;
1975 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301976 //Open the module session, if not opened already.
Vidyakumar Athota4f392512017-05-15 18:03:40 -07001977 status = audio_extn_qaf_session_open(mmtype, out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301978 qaf_mod = &(p_qaf->qaf_mod[mmtype]);
1979
1980 if ((status != 0) || (qaf_mod->session_handle == NULL)) {
1981 ERROR_MSG("Failed to open session.");
1982 return status;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301983 }
1984
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301985 audio_stream_config_t input_config;
1986 input_config.sample_rate = config->sample_rate;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301987 input_config.channels = popcount(config->channel_mask);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301988 input_config.format = config->format;
1989
Harsh Bansal28718c52017-04-20 13:47:12 +05301990 if (input_config.format != AUDIO_FORMAT_PCM_16_BIT) {
1991 input_config.format &= AUDIO_FORMAT_MAIN_MASK;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301992 }
1993
Harsh Bansal28718c52017-04-20 13:47:12 +05301994 DEBUG_MSG("stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)",
1995 input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301996
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301997 if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301998 //If PCM stream is already opened then fail this stream open.
1999 if (qaf_mod->stream_in[QAF_IN_PCM]) {
2000 ERROR_MSG("PCM input is already active.");
2001 return -ENOTSUP;
2002 }
2003
2004 //TODO: Flag can be system tone or external associated PCM.
2005 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
2006 &out->qaf_stream_handle,
2007 input_config,
2008 devices,
2009 AUDIO_STREAM_SYSTEM_TONE);
Harsh Bansalc83207c2017-09-01 16:04:36 +05302010 if (status == 0) {
2011 qaf_mod->stream_in[QAF_IN_PCM] = out;
2012 } else {
2013 ERROR_MSG("System tone stream open failed with QAF module !!!");
2014 }
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302015 } else if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
2016 if (is_main_active(qaf_mod) || is_dual_main_active(qaf_mod)) {
2017 ERROR_MSG("Dual Main or Main already active. So, Cannot open main and associated stream");
2018 return -EINVAL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302019 } else {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302020 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
2021 if (status == 0) {
2022 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);
2023 qaf_mod->stream_in[QAF_IN_MAIN] = out;
2024 } else {
2025 ERROR_MSG("Stream Open FAILED !!!");
2026 }
2027 }
Naresh Tanniru908d9a02017-05-17 14:12:48 +05302028 } else if ((flags & AUDIO_OUTPUT_FLAG_MAIN) || ((!(flags & AUDIO_OUTPUT_FLAG_MAIN)) && (!(flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)))) {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302029 /* Assume Main if no flag is set */
2030 if (is_dual_main_active(qaf_mod)) {
2031 ERROR_MSG("Dual Main already active. So, Cannot open main stream");
2032 return -EINVAL;
2033 } else if (is_main_active(qaf_mod) && qaf_mod->stream_in[QAF_IN_ASSOC]) {
2034 ERROR_MSG("Main and Associated already active. So, Cannot open main stream");
2035 return -EINVAL;
2036 } else if (is_main_active(qaf_mod) && (mmtype != MS12)) {
2037 ERROR_MSG("Main already active and Not an MS12 format. So, Cannot open another main stream");
2038 return -EINVAL;
2039 } else {
2040 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
2041 if (status == 0) {
2042 DEBUG_MSG("Open stream for Input with only Main flag(%x) stream_handle(%p)", flags, out->qaf_stream_handle);
2043 if(qaf_mod->stream_in[QAF_IN_MAIN]) {
2044 qaf_mod->stream_in[QAF_IN_MAIN_2] = out;
2045 } else {
2046 qaf_mod->stream_in[QAF_IN_MAIN] = out;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302047 }
2048 } else {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302049 ERROR_MSG("Stream Open FAILED !!!");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302050 }
2051 }
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302052 } else if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
2053 if (is_dual_main_active(qaf_mod)) {
2054 ERROR_MSG("Dual Main already active. So, Cannot open associated stream");
2055 return -EINVAL;
2056 } else if (!is_main_active(qaf_mod)) {
2057 ERROR_MSG("Main not active. So, Cannot open associated stream");
2058 return -EINVAL;
2059 } else if (qaf_mod->stream_in[QAF_IN_ASSOC]) {
2060 ERROR_MSG("Associated already active. So, Cannot open associated stream");
2061 return -EINVAL;
2062 }
2063 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
2064 if (status == 0) {
2065 DEBUG_MSG("Open stream for Input with only Associated flag(%x) stream handle(%p)", flags, out->qaf_stream_handle);
2066 qaf_mod->stream_in[QAF_IN_ASSOC] = out;
2067 } else {
2068 ERROR_MSG("Stream Open FAILED !!!");
2069 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302070 }
2071
Harsh Bansal28718c52017-04-20 13:47:12 +05302072 if (status != 0) {
2073 //If no stream is active then close the session.
2074 qaf_session_close(qaf_mod);
2075 return status;
2076 }
2077
2078 //If Device is HDMI, QAF passthrough is enabled and there is no previous QAF passthrough input stream.
2079 if ((!p_qaf->passthrough_in)
2080 && (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
2081 && audio_extn_qaf_passthrough_enabled(out)) {
2082 //Assign the QAF passthrough input stream.
2083 p_qaf->passthrough_in = out;
2084
2085 //If HDMI is connected and format is supported by HDMI then create QAF passthrough output stream.
2086 if (p_qaf->hdmi_connect
2087 && platform_is_edid_supported_format(p_qaf->adev->platform, out->format)) {
2088 status = create_qaf_passthrough_stream();
2089 if (status < 0) {
2090 qaf_stream_close(out);
2091 ERROR_MSG("QAF passthrough stream creation failed with error %d", status);
2092 return status;
2093 }
2094 }
2095 /*Else: since QAF passthrough input stream is already initialized,
2096 * when hdmi is connected
2097 * then qaf passthrough output stream will be created.
2098 */
2099 }
2100
2101 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302102 return status;
2103}
2104
Harsh Bansal28718c52017-04-20 13:47:12 +05302105/* Resume a QAF stream. */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302106static int qaf_out_resume(struct audio_stream_out* stream)
2107{
2108 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05302109 int status = 0;
2110 DEBUG_MSG("Output Stream %p", out);
2111
2112
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302113 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05302114
2115 //If QAF passthrough is active then block the resume on module input streams.
2116 if (p_qaf->passthrough_out) {
2117 //If resume is received for the QAF passthrough stream then call the primary HAL api.
2118 pthread_mutex_lock(&p_qaf->lock);
2119 if (p_qaf->passthrough_in == out) {
2120 status = p_qaf->passthrough_out->stream.resume(
2121 (struct audio_stream_out*)p_qaf->passthrough_out);
2122 if (!status) out->offload_state = OFFLOAD_STATE_PLAYING;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302123 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302124 pthread_mutex_unlock(&p_qaf->lock);
2125 } else {
2126 //Flush the module input stream.
2127 status = qaf_stream_start(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302128 }
2129
Harsh Bansal28718c52017-04-20 13:47:12 +05302130 unlock_output_stream(out);
2131
2132 DEBUG_MSG();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302133 return status;
2134}
2135
Harsh Bansal28718c52017-04-20 13:47:12 +05302136/* Offload thread for QAF output streams. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302137static void *qaf_offload_thread_loop(void *context)
2138{
Harsh Bansal28718c52017-04-20 13:47:12 +05302139 struct stream_out *out = (struct stream_out *)context;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302140 struct listnode *item;
2141 int ret = 0;
2142 struct str_parms *parms = NULL;
2143 int value = 0;
2144 char* kvpairs = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05302145 struct qaf_module *qaf_mod = NULL;
2146
2147 qaf_mod = get_qaf_module_for_input_stream(out);
2148
2149 if (!qaf_mod) return NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302150
2151 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
2152 set_sched_policy(0, SP_FOREGROUND);
2153 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
2154
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302155 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05302156
2157 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302158 for (;;) {
2159 struct offload_cmd *cmd = NULL;
2160 stream_callback_event_t event;
2161 bool send_callback = false;
2162
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302163 DEBUG_MSG_VV("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302164 if (list_empty(&out->qaf_offload_cmd_list)) {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302165 DEBUG_MSG_VV("SLEEPING");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302166 pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302167 DEBUG_MSG_VV("RUNNING");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302168 continue;
2169 }
2170
2171 item = list_head(&out->qaf_offload_cmd_list);
2172 cmd = node_to_item(item, struct offload_cmd, node);
2173 list_remove(item);
2174
2175 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
2176 free(cmd);
2177 break;
2178 }
2179
Harsh Bansal28718c52017-04-20 13:47:12 +05302180 unlock_output_stream(out);
2181
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302182 send_callback = false;
Harsh Bansal28718c52017-04-20 13:47:12 +05302183 switch (cmd->cmd) {
2184 case OFFLOAD_CMD_WAIT_FOR_BUFFER: {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302185 DEBUG_MSG_VV("wait for buffer availability");
Harsh Bansal28718c52017-04-20 13:47:12 +05302186
2187 while (1) {
2188 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle,
2189 "buf_available");
2190 if (kvpairs) {
2191 parms = str_parms_create_str(kvpairs);
2192 ret = str_parms_get_int(parms, "buf_available", &value);
2193 if (ret >= 0) {
Harsh Bansal7c09d5d2017-08-04 14:20:37 +05302194 if (value > 0) {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302195 DEBUG_MSG_VV("buffer available");
Harsh Bansal28718c52017-04-20 13:47:12 +05302196 str_parms_destroy(parms);
2197 parms = NULL;
2198 break;
2199 } else {
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302200 DEBUG_MSG_VV("sleep");
Harsh Bansal28718c52017-04-20 13:47:12 +05302201 str_parms_destroy(parms);
2202 parms = NULL;
2203 usleep(10000);
2204 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302205 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302206 free(kvpairs);
2207 kvpairs = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302208 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302209 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302210 send_callback = true;
2211 event = STREAM_CBK_EVENT_WRITE_READY;
2212 break;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302213 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302214 default:
2215 DEBUG_MSG("unknown command received: %d", cmd->cmd);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302216 break;
2217 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302218
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302219 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05302220
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002221 if (send_callback && out->client_callback) {
2222 out->client_callback(event, NULL, out->client_cookie);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302223 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302224
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302225 free(cmd);
2226 }
2227
2228 while (!list_empty(&out->qaf_offload_cmd_list)) {
2229 item = list_head(&out->qaf_offload_cmd_list);
2230 list_remove(item);
Harsh Bansal28718c52017-04-20 13:47:12 +05302231 free (node_to_item( item, struct offload_cmd, node));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302232 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302233 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302234
2235 return NULL;
2236}
2237
Harsh Bansal28718c52017-04-20 13:47:12 +05302238/* Create the offload callback thread for QAF output stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302239static int qaf_create_offload_callback_thread(struct stream_out *out)
2240{
Harsh Bansal28718c52017-04-20 13:47:12 +05302241 DEBUG_MSG("Output Stream %p", out);
2242 lock_output_stream(out);
2243 pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *)NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302244 list_init(&out->qaf_offload_cmd_list);
Harsh Bansal28718c52017-04-20 13:47:12 +05302245 pthread_create(&out->qaf_offload_thread,
2246 (const pthread_attr_t *)NULL,
2247 qaf_offload_thread_loop,
2248 out);
2249 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302250 return 0;
2251}
2252
Harsh Bansal28718c52017-04-20 13:47:12 +05302253/* Destroy the offload callback thread of QAF output stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302254static int qaf_destroy_offload_callback_thread(struct stream_out *out)
2255{
Harsh Bansal28718c52017-04-20 13:47:12 +05302256 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302257 qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302258
Harsh Bansal28718c52017-04-20 13:47:12 +05302259 pthread_join(out->qaf_offload_thread, (void **)NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302260 pthread_cond_destroy(&out->qaf_offload_cond);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302261 return 0;
2262}
2263
Harsh Bansal28718c52017-04-20 13:47:12 +05302264/* Sets the stream set parameters (device routing information). */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302265static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
2266{
2267 struct str_parms *parms, *new_parms;
2268 char value[32];
2269 char *new_kv_pairs;
2270 int val = 0;
2271 struct stream_out *out = (struct stream_out *)stream;
2272 int ret = 0;
2273 int err = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +05302274 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302275
Harsh Bansal28718c52017-04-20 13:47:12 +05302276 DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302277
Harsh Bansal28718c52017-04-20 13:47:12 +05302278 parms = str_parms_create_str(kvpairs);
2279 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
2280 if (err < 0)
2281 return err;
2282 val = atoi(value);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302283
Harsh Bansal28718c52017-04-20 13:47:12 +05302284 qaf_mod = get_qaf_module_for_input_stream(out);
2285 if (!qaf_mod) return (-EINVAL);
2286
2287 //TODO: HDMI is connected but user doesn't want HDMI output, close both HDMI outputs.
2288
2289 /* Setting new device information to the mm module input streams.
2290 * This is needed if QAF module output streams are not created yet.
2291 */
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302292 out->devices = val;
Harsh Bansal28718c52017-04-20 13:47:12 +05302293
2294 if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
2295 //If device is BT then open the BT stream if not already opened.
2296 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL
2297 && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
2298 ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
2299 QAF_OUTPUT_SAMPLING_RATE,
2300 AUDIO_CHANNEL_OUT_STEREO,
2301 CODEC_BACKEND_DEFAULT_BIT_WIDTH);
2302 if (ret != 0) {
2303 ERROR_MSG("BT Output stream open failure!");
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302304 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302305 }
2306 } else if (val != 0) {
2307 //If device is not BT then close the BT stream if already opened.
2308 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
2309 audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302310 }
2311 }
2312
Harsh Bansal28718c52017-04-20 13:47:12 +05302313 if (p_qaf->passthrough_in == out) { //Device routing is received for QAF passthrough stream.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302314
Harsh Bansal28718c52017-04-20 13:47:12 +05302315 if (!(val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { //HDMI route is disabled.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302316
Harsh Bansal28718c52017-04-20 13:47:12 +05302317 //If QAF pasthrough output is enabled. Close it.
2318 close_qaf_passthrough_stream();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302319
Harsh Bansal28718c52017-04-20 13:47:12 +05302320 //Send the routing information to mm module pcm output.
2321 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
2322 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
2323 (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302324 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302325 //else: device info is updated in the input streams.
2326 } else { //HDMI route is enabled.
2327
2328 //create the QAf passthrough stream, if not created already.
2329 ret = create_qaf_passthrough_stream();
2330
2331 if (p_qaf->passthrough_out != NULL) { //If QAF passthrough out is enabled then send routing information.
2332 ret = p_qaf->passthrough_out->stream.common.set_parameters(
2333 (struct audio_stream *)p_qaf->passthrough_out, kvpairs);
2334 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302335 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302336 } else {
2337 //Send the routing information to mm module pcm output.
2338 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
2339 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
2340 (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
2341 }
2342 //else: device info is updated in the input streams.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302343 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302344 str_parms_destroy(parms);
2345
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002346 return ret;
2347}
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302348
Harsh Bansal28718c52017-04-20 13:47:12 +05302349/* Checks if a stream is QAF stream or not. */
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002350bool audio_extn_is_qaf_stream(struct stream_out *out)
2351{
Harsh Bansal28718c52017-04-20 13:47:12 +05302352 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002353
Harsh Bansal28718c52017-04-20 13:47:12 +05302354 if (qaf_mod) {
2355 return true;
2356 }
2357 return false;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002358}
2359
2360/* API to send playback stream specific config parameters */
2361int audio_extn_qaf_out_set_param_data(struct stream_out *out,
Harsh Bansal28718c52017-04-20 13:47:12 +05302362 audio_extn_param_id param_id,
2363 audio_extn_param_payload *payload)
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002364{
2365 int ret = -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05302366 int index;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002367 struct stream_out *new_out = NULL;
2368 struct audio_adsp_event *adsp_event;
Harsh Bansal28718c52017-04-20 13:47:12 +05302369 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002370
Harsh Bansal28718c52017-04-20 13:47:12 +05302371 if (!out || !qaf_mod || !payload) {
2372 ERROR_MSG("Invalid Param");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002373 return ret;
2374 }
2375
2376 /* In qaf output render session may not be opened at this time.
Harsh Bansal28718c52017-04-20 13:47:12 +05302377 to handle it store adsp_hdlr param info so that it can be
2378 applied later after opening render session from ms12 callback
2379 */
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002380 if (param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302381 index = get_input_stream_index(out);
2382 if (index < 0) {
2383 ERROR_MSG("Invalid stream");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002384 return ret;
2385 }
2386 adsp_event = (struct audio_adsp_event *)payload;
2387
Harsh Bansal28718c52017-04-20 13:47:12 +05302388 if (payload->adsp_event_params.payload_length <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
2389 pthread_mutex_lock(&p_qaf->lock);
2390 memcpy(qaf_mod->adsp_hdlr_config[index].event_payload,
2391 adsp_event->payload,
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002392 adsp_event->payload_length);
Harsh Bansal28718c52017-04-20 13:47:12 +05302393 qaf_mod->adsp_hdlr_config[index].event_params.payload =
2394 qaf_mod->adsp_hdlr_config[index].event_payload;
2395 qaf_mod->adsp_hdlr_config[index].event_params.payload_length =
2396 adsp_event->payload_length;
2397 qaf_mod->adsp_hdlr_config[index].adsp_hdlr_config_valid = true;
2398 pthread_mutex_unlock(&p_qaf->lock);
2399 } else {
2400 ERROR_MSG("Invalid adsp event length %d", adsp_event->payload_length);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002401 return ret;
2402 }
2403 ret = 0;
2404 }
2405
Harsh Bansal28718c52017-04-20 13:47:12 +05302406 /* apply param for all active out sessions */
2407 for (index = 0; index < MAX_QAF_MODULE_OUT; index++) {
2408 new_out = qaf_mod->stream_out[index];
2409 if (!new_out) continue;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002410
Harsh Bansal28718c52017-04-20 13:47:12 +05302411 /*ADSP event is not supported for passthrough*/
2412 if ((param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD)
2413 && !(new_out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) continue;
2414 if (new_out->standby)
2415 new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
2416 lock_output_stream(new_out);
2417 ret = audio_extn_out_set_param_data(new_out, param_id, payload);
2418 if (ret)
2419 ERROR_MSG("audio_extn_out_set_param_data error %d", ret);
2420 unlock_output_stream(new_out);
2421 }
2422 return ret;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002423}
2424
2425int audio_extn_qaf_out_get_param_data(struct stream_out *out,
2426 audio_extn_param_id param_id,
2427 audio_extn_param_payload *payload)
2428{
Harsh Bansal28718c52017-04-20 13:47:12 +05302429 int ret = -EINVAL, i;
2430 struct stream_out *new_out;
2431 struct audio_usecase *uc_info;
2432 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002433
Harsh Bansal28718c52017-04-20 13:47:12 +05302434 if (!out || !qaf_mod || !payload) {
2435 ERROR_MSG("Invalid Param");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002436 return ret;
2437 }
2438
Harsh Bansal28718c52017-04-20 13:47:12 +05302439 if (!p_qaf->hdmi_connect) {
2440 ERROR_MSG("hdmi not connected");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002441 return ret;
2442 }
2443
2444 /* get session which is routed to hdmi*/
Harsh Bansal28718c52017-04-20 13:47:12 +05302445 if (p_qaf->passthrough_out)
2446 new_out = p_qaf->passthrough_out;
2447 else {
2448 for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
2449 if (qaf_mod->stream_out[i]) {
2450 new_out = qaf_mod->stream_out[i];
2451 break;
2452 }
2453 }
2454 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002455
2456 if (!new_out) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302457 ERROR_MSG("No stream active.");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002458 return ret;
2459 }
2460
2461 if (new_out->standby)
Harsh Bansal28718c52017-04-20 13:47:12 +05302462 new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002463
2464 lock_output_stream(new_out);
2465 ret = audio_extn_out_get_param_data(new_out, param_id, payload);
Harsh Bansal28718c52017-04-20 13:47:12 +05302466 if (ret)
2467 ERROR_MSG("audio_extn_out_get_param_data error %d", ret);
2468 unlock_output_stream(new_out);
2469
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302470 return ret;
2471}
2472
Harsh Bansal28718c52017-04-20 13:47:12 +05302473/* To open a stream with QAF. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302474int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
Harsh Bansal28718c52017-04-20 13:47:12 +05302475 audio_io_handle_t handle,
2476 audio_devices_t devices,
2477 audio_output_flags_t flags,
2478 struct audio_config *config,
2479 struct audio_stream_out **stream_out,
2480 const char *address)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302481{
2482 int ret = 0;
2483 struct stream_out *out;
2484
2485 ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
2486 if (*stream_out == NULL) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302487 ERROR_MSG("Stream open failed %d", ret);
Deepak Agarwal1e42b852017-02-11 17:57:04 +05302488 return ret;
2489 }
2490
Harsh Bansal28718c52017-04-20 13:47:12 +05302491 out = (struct stream_out *)*stream_out;
2492
2493 ret = qaf_stream_open(out, config, flags, devices);
2494 if (ret == -ENOTSUP) {
2495 //Stream not supported by QAF, Bypass QAF.
2496 return 0;
2497 } else if (ret < 0) {
2498 ERROR_MSG("Error opening QAF stream err[%d]!", ret);
2499 adev_close_output_stream(dev, *stream_out);
2500 return ret;
2501 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302502
2503 /* Override function pointers based on qaf definitions */
2504 out->stream.set_volume = qaf_out_set_volume;
2505 out->stream.pause = qaf_out_pause;
2506 out->stream.resume = qaf_out_resume;
2507 out->stream.drain = qaf_out_drain;
2508 out->stream.flush = qaf_out_flush;
2509
2510 out->stream.common.standby = qaf_out_standby;
2511 out->stream.common.set_parameters = qaf_out_set_parameters;
2512 out->stream.get_latency = qaf_out_get_latency;
2513 out->stream.write = qaf_out_write;
2514 out->stream.get_presentation_position = qaf_out_get_presentation_position;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302515 out->platform_latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302516
Harsh Bansal28718c52017-04-20 13:47:12 +05302517 /*TODO: Need to handle this for DTS*/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302518 if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
2519 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
Varun B34da7a42017-02-13 16:16:53 +05302520 out->config.period_size = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302521 out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
Varun B34da7a42017-02-13 16:16:53 +05302522 out->config.start_threshold = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
2523 out->config.avail_min = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302524 } else if(out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
2525 out->compr_config.fragment_size = qaf_get_pcm_offload_input_buffer_size(&(config->offload_info));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302526 }
Satish Babu Patakokilaa8c136d2017-04-21 12:48:19 +05302527
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302528 *stream_out = &out->stream;
2529 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
2530 qaf_create_offload_callback_thread(out);
2531 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302532
2533 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302534 return 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302535}
2536
Harsh Bansal28718c52017-04-20 13:47:12 +05302537/* Close a QAF stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302538void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
Harsh Bansal28718c52017-04-20 13:47:12 +05302539 struct audio_stream_out *stream)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302540{
2541 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05302542 struct qaf_module* qaf_mod = get_qaf_module_for_input_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302543
Harsh Bansal28718c52017-04-20 13:47:12 +05302544 if (!qaf_mod) return;
2545
2546 DEBUG_MSG("stream_handle(%p) format = %x", out, out->format);
2547
2548 //If close is received for QAF passthrough stream then close the QAF passthrough output.
2549 if (p_qaf->passthrough_in == out) {
2550 if (p_qaf->passthrough_out) {
2551 ALOGD("%s %d closing stream handle %p", __func__, __LINE__, p_qaf->passthrough_out);
2552 pthread_mutex_lock(&p_qaf->lock);
2553 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
2554 (struct audio_stream_out *)(p_qaf->passthrough_out));
2555 pthread_mutex_unlock(&p_qaf->lock);
2556 p_qaf->passthrough_out = NULL;
2557 }
2558
2559 p_qaf->passthrough_in = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302560 }
2561
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302562 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
2563 qaf_destroy_offload_callback_thread(out);
2564 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002565
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302566 qaf_stream_close(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302567
2568 adev_close_output_stream(dev, stream);
Harsh Bansal28718c52017-04-20 13:47:12 +05302569
2570 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302571}
2572
Harsh Bansal28718c52017-04-20 13:47:12 +05302573/* Check if QAF is supported or not. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302574bool audio_extn_qaf_is_enabled()
2575{
2576 bool prop_enabled = false;
2577 char value[PROPERTY_VALUE_MAX] = {0};
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07002578 property_get("vendor.audio.qaf.enabled", value, NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302579 prop_enabled = atoi(value) || !strncmp("true", value, 4);
2580 return (prop_enabled);
2581}
2582
Harsh Bansal28718c52017-04-20 13:47:12 +05302583/* Query HDMI EDID and sets module output accordingly.*/
2584void set_hdmi_configuration_to_module()
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302585{
Harsh Bansal28718c52017-04-20 13:47:12 +05302586 int channels = 0;
2587 char *format_params;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302588 struct str_parms *qaf_params;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302589 char prop_value[PROPERTY_VALUE_MAX];
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302590 bool passth_support = false;
2591
Harsh Bansal28718c52017-04-20 13:47:12 +05302592 DEBUG_MSG("Entry");
2593
2594 if (!p_qaf) {
2595 return;
2596 }
2597
2598 if (!p_qaf->hdmi_connect) {
2599 DEBUG_MSG("HDMI is not connected.");
2600 return;
2601 }
2602
2603 p_qaf->hdmi_sink_channels = 0;
2604
2605 //QAF re-encoding and DSP offload passthrough is supported.
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07002606 if (property_get_bool("vendor.audio.offload.passthrough", false)
2607 && property_get_bool("vendor.audio.qaf.reencode", false)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302608
2609 //If MS12 session is active.
2610 if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
2611
2612 bool do_setparam = false;
2613 qaf_params = str_parms_create();
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07002614 property_get("vendor.audio.qaf.hdmi.out", prop_value, NULL);
Harsh Bansal28718c52017-04-20 13:47:12 +05302615
2616 if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_E_AC3)
2617 && (strncmp(prop_value, "ddp", 3) == 0)) {
2618 do_setparam = true;
2619 if (qaf_params) {
2620 str_parms_add_str(qaf_params,
2621 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2622 AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
2623 }
2624 } else if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_AC3)) {
2625 do_setparam = true;
2626 if (qaf_params) {
2627 str_parms_add_str(qaf_params,
2628 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2629 AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
2630 }
2631 }
2632
2633 if (do_setparam) {
2634 if (p_qaf->qaf_msmd_enabled) {
2635 str_parms_add_str(qaf_params,
2636 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2637 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
2638 } else {
2639 str_parms_add_str(qaf_params,
2640 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2641 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2642 }
2643 format_params = str_parms_to_str(qaf_params);
2644
2645 p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
2646 format_params);
2647
2648 passth_support = true;
2649 }
2650 str_parms_destroy(qaf_params);
2651 }
2652
2653 //DTS_M8 session is active.
2654 if (p_qaf->qaf_mod[DTS_M8].session_handle
2655 && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
2656
2657 bool do_setparam = false;
2658 qaf_params = str_parms_create();
Harsh Bansal28718c52017-04-20 13:47:12 +05302659 if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_DTS)) {
2660 do_setparam = true;
2661 if (qaf_params) {
2662 str_parms_add_str(qaf_params,
2663 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2664 AUDIO_QAF_PARAMETER_VALUE_REENCODE_DTS);
2665 }
2666 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302667
2668 if (do_setparam) {
2669 if (p_qaf->qaf_msmd_enabled) {
2670 str_parms_add_str(qaf_params,
2671 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2672 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
2673 } else {
2674 str_parms_add_str(qaf_params,
2675 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2676 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2677 }
2678 format_params = str_parms_to_str(qaf_params);
2679
2680 p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
2681 format_params);
2682
2683 passth_support = true;
2684 }
2685 str_parms_destroy(qaf_params);
2686 }
2687 }
2688
2689 //Compressed passthrough is not enabled.
2690 if (!passth_support) {
2691
2692 channels = platform_edid_get_max_channels(p_qaf->adev->platform);
2693
2694 qaf_params = str_parms_create();
Harsh Bansal431eede2017-04-28 21:22:30 +05302695
2696 str_parms_add_str(qaf_params,
2697 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2698 AUDIO_QAF_PARAMETER_VALUE_PCM);
Harsh Bansal28718c52017-04-20 13:47:12 +05302699 switch (channels) {
2700 case 8:
2701 DEBUG_MSG("Switching Qaf output to 7.1 channels");
2702 str_parms_add_str(qaf_params,
2703 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2704 AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
2705 if (p_qaf->qaf_msmd_enabled) {
2706 str_parms_add_str(qaf_params,
2707 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2708 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2709 } else {
2710 str_parms_add_str(qaf_params,
2711 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2712 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2713 }
2714 p_qaf->hdmi_sink_channels = channels;
2715 break;
2716 case 6:
2717 DEBUG_MSG("Switching Qaf output to 5.1 channels");
2718 str_parms_add_str(qaf_params,
2719 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2720 AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
2721 if (p_qaf->qaf_msmd_enabled) {
2722 str_parms_add_str(qaf_params,
2723 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2724 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2725 } else {
2726 str_parms_add_str(qaf_params,
2727 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2728 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2729 }
2730 p_qaf->hdmi_sink_channels = channels;
2731 break;
2732 default:
2733 DEBUG_MSG("Switching Qaf output to default channels");
2734 str_parms_add_str(qaf_params,
2735 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2736 AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
2737 if (p_qaf->qaf_msmd_enabled) {
2738 str_parms_add_str(qaf_params,
2739 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2740 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2741 } else {
2742 str_parms_add_str(qaf_params,
2743 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2744 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
2745 }
2746 p_qaf->hdmi_sink_channels = 2;
2747 break;
2748 }
2749
2750 format_params = str_parms_to_str(qaf_params);
2751
2752 if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
2753 p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
2754 format_params);
2755 }
2756 if (p_qaf->qaf_mod[DTS_M8].session_handle
2757 && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
2758 p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
2759 format_params);
2760 }
2761
2762 str_parms_destroy(qaf_params);
2763 }
2764 DEBUG_MSG("Exit");
2765}
2766
2767/* QAF set parameter function. For Device connect and disconnect. */
2768int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
2769{
2770 int status = 0, val = 0, k;
2771 char *format_params, *kv_parirs;
2772 struct str_parms *qaf_params;
2773 char value[32];
2774
2775 DEBUG_MSG("Entry");
2776
2777 if (!p_qaf) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302778 return -EINVAL;
2779 }
2780
2781 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
Harsh Bansal28718c52017-04-20 13:47:12 +05302782
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302783 if (status >= 0) {
2784 val = atoi(value);
Harsh Bansal28718c52017-04-20 13:47:12 +05302785 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is connected.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302786
Harsh Bansal28718c52017-04-20 13:47:12 +05302787 p_qaf->hdmi_connect = 1;
2788 p_qaf->hdmi_sink_channels = 0;
2789
2790 if (p_qaf->passthrough_in) { //If QAF passthrough is already initialized.
2791 lock_output_stream(p_qaf->passthrough_in);
2792 if (platform_is_edid_supported_format(adev->platform,
2793 p_qaf->passthrough_in->format)) {
2794 //If passthrough format is supported by HDMI then create the QAF passthrough output if not created already.
2795 create_qaf_passthrough_stream();
2796 //Ignoring the returned error, If error then QAF passthrough is disabled.
2797 } else {
2798 //If passthrough format is not supported by HDMI then close the QAF passthrough output if already created.
2799 close_qaf_passthrough_stream();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302800 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302801 unlock_output_stream(p_qaf->passthrough_in);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302802 }
2803
Harsh Bansal28718c52017-04-20 13:47:12 +05302804 set_hdmi_configuration_to_module();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302805
Bharath Gopal01310bb2016-12-05 15:39:32 +05302806 } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302807 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2808 if (!p_qaf->qaf_mod[k].bt_hdl) {
2809 DEBUG_MSG("Opening a2dp output...");
2810 status = audio_extn_bt_hal_load(&p_qaf->qaf_mod[k].bt_hdl);
2811 if (status != 0) {
2812 ERROR_MSG("Error opening BT module");
2813 return status;
2814 }
2815 }
Bharath Gopal01310bb2016-12-05 15:39:32 +05302816 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302817 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302818 //TODO else if: Need to consider other devices.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302819 }
2820
2821 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
2822 if (status >= 0) {
2823 val = atoi(value);
Harsh Bansal28718c52017-04-20 13:47:12 +05302824 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is disconnected.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302825
Harsh Bansal28718c52017-04-20 13:47:12 +05302826 qaf_params = str_parms_create();
2827 str_parms_add_str(qaf_params,
2828 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2829 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
2830 str_parms_add_str(qaf_params,
2831 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2832 AUDIO_QAF_PARAMETER_VALUE_PCM);
2833 p_qaf->hdmi_sink_channels = 0;
2834
2835 p_qaf->passthrough_enabled = 0;
2836 p_qaf->mch_pcm_hdmi_enabled = 0;
2837 p_qaf->hdmi_connect = 0;
2838
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302839 format_params = str_parms_to_str(qaf_params);
Harsh Bansal28718c52017-04-20 13:47:12 +05302840
2841 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2842 if (p_qaf->qaf_mod[k].session_handle
2843 && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
2844 p_qaf->qaf_mod[k].qaf_audio_session_set_param(
2845 p_qaf->qaf_mod[k].session_handle, format_params);
2846 }
2847 }
2848 close_all_hdmi_output();
2849
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302850 str_parms_destroy(qaf_params);
Harsh Bansal28718c52017-04-20 13:47:12 +05302851 close_qaf_passthrough_stream();
Bharath Gopal01310bb2016-12-05 15:39:32 +05302852 } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302853 DEBUG_MSG("Closing a2dp output...");
2854 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2855 if (p_qaf->qaf_mod[k].bt_hdl) {
2856 audio_extn_bt_hal_unload(p_qaf->qaf_mod[k].bt_hdl);
2857 p_qaf->qaf_mod[k].bt_hdl = NULL;
2858 }
2859 }
2860 }
2861 //TODO else if: Need to consider other devices.
2862 }
2863
2864 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2865 kv_parirs = str_parms_to_str(parms);
2866 if (p_qaf->qaf_mod[k].session_handle && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
2867 p_qaf->qaf_mod[k].qaf_audio_session_set_param(
2868 p_qaf->qaf_mod[k].session_handle, kv_parirs);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302869 }
2870 }
2871
Harsh Bansal28718c52017-04-20 13:47:12 +05302872 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302873 return status;
2874}
2875
Harsh Bansal28718c52017-04-20 13:47:12 +05302876/* Create the QAF. */
2877int audio_extn_qaf_init(struct audio_device *adev)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302878{
Harsh Bansal28718c52017-04-20 13:47:12 +05302879 DEBUG_MSG("Entry");
2880
2881 p_qaf = calloc(1, sizeof(struct qaf));
2882 if (p_qaf == NULL) {
2883 ERROR_MSG("Out of memory");
2884 return -ENOMEM;
2885 }
2886
2887 p_qaf->adev = adev;
2888
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07002889 if (property_get_bool("vendor.audio.qaf.msmd", false)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302890 p_qaf->qaf_msmd_enabled = 1;
2891 }
2892 pthread_mutex_init(&p_qaf->lock, (const pthread_mutexattr_t *) NULL);
2893
2894 int i = 0;
2895
2896 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
2897 char value[PROPERTY_VALUE_MAX] = {0};
2898 char lib_name[PROPERTY_VALUE_MAX] = {0};
2899 struct qaf_module *qaf_mod = &(p_qaf->qaf_mod[i]);
2900
2901 if (i == MS12) {
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07002902 property_get("vendor.audio.qaf.library", value, NULL);
Vidyakumar Athota4f392512017-05-15 18:03:40 -07002903 snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
2904#ifdef AUDIO_EXTN_IP_HDLR_ENABLED
2905{
2906 int ret = 0;
2907 ret = audio_extn_ip_hdlr_intf_init(&qaf_mod->ip_hdlr_hdl, lib_name, &qaf_mod->qaf_lib,
2908 adev, USECASE_AUDIO_PLAYBACK_OFFLOAD);
2909 if (ret < 0) {
2910 ERROR_MSG("audio_extn_ip_hdlr_intf_init failed, ret = %d", ret);
Harsh Bansal28718c52017-04-20 13:47:12 +05302911 continue;
2912 }
Vidyakumar Athota4f392512017-05-15 18:03:40 -07002913 if (qaf_mod->qaf_lib == NULL) {
2914 ERROR_MSG("failed to get library handle");
2915 continue;
2916 }
2917}
2918#else
Harsh Bansal28718c52017-04-20 13:47:12 +05302919 qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
2920 if (qaf_mod->qaf_lib == NULL) {
2921 ERROR_MSG("DLOPEN failed for %s", lib_name);
2922 continue;
2923 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302924 DEBUG_MSG("DLOPEN successful for %s", lib_name);
Vidyakumar Athota4f392512017-05-15 18:03:40 -07002925#endif
2926 } else if (i == DTS_M8) {
2927 property_get("audio.qaf.m8.library", value, NULL);
2928 snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
2929 qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
2930 if (qaf_mod->qaf_lib == NULL) {
2931 ERROR_MSG("DLOPEN failed for %s", lib_name);
2932 continue;
2933 }
2934 DEBUG_MSG("DLOPEN successful for %s", lib_name);
2935 } else {
2936 continue;
2937 }
2938
Harsh Bansal28718c52017-04-20 13:47:12 +05302939 qaf_mod->qaf_audio_session_open =
Sri Karri1fbfef52017-06-29 19:45:47 +05302940 (int (*)(audio_session_handle_t* session_handle, audio_session_type_t s_type,
2941 void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
Harsh Bansal28718c52017-04-20 13:47:12 +05302942 "audio_session_open");
2943 qaf_mod->qaf_audio_session_close =
2944 (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
2945 "audio_session_close");
2946 qaf_mod->qaf_audio_stream_open =
2947 (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
2948 audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
2949 "audio_stream_open");
2950 qaf_mod->qaf_audio_stream_close =
2951 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2952 "audio_stream_close");
2953 qaf_mod->qaf_audio_stream_set_param =
2954 (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
2955 "audio_stream_set_param");
2956 qaf_mod->qaf_audio_session_set_param =
2957 (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
2958 "audio_session_set_param");
2959 qaf_mod->qaf_audio_stream_get_param =
2960 (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
2961 "audio_stream_get_param");
2962 qaf_mod->qaf_audio_session_get_param =
2963 (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
2964 "audio_session_get_param");
2965 qaf_mod->qaf_audio_stream_start =
2966 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2967 "audio_stream_start");
2968 qaf_mod->qaf_audio_stream_stop =
2969 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2970 "audio_stream_stop");
2971 qaf_mod->qaf_audio_stream_pause =
2972 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2973 "audio_stream_pause");
2974 qaf_mod->qaf_audio_stream_flush =
2975 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2976 "audio_stream_flush");
2977 qaf_mod->qaf_audio_stream_write =
2978 (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
2979 "audio_stream_write");
2980 qaf_mod->qaf_register_event_callback =
2981 (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
2982 audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
2983 "register_event_callback");
2984 }
2985
2986 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302987 return 0;
2988}
2989
Harsh Bansal28718c52017-04-20 13:47:12 +05302990/* Tear down the qaf extension. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302991void audio_extn_qaf_deinit()
2992{
Harsh Bansal28718c52017-04-20 13:47:12 +05302993 int i;
2994 DEBUG_MSG("Entry");
2995
2996 if (p_qaf != NULL) {
2997 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
2998 qaf_session_close(&p_qaf->qaf_mod[i]);
2999
3000 if (p_qaf->qaf_mod[i].qaf_lib != NULL) {
Vidyakumar Athota4f392512017-05-15 18:03:40 -07003001 if (i == MS12) {
3002#ifdef AUDIO_EXTN_IP_HDLR_ENABLED
3003 audio_extn_ip_hdlr_intf_deinit(p_qaf->qaf_mod[i].ip_hdlr_hdl);
3004#else
3005 dlclose(p_qaf->qaf_mod[i].qaf_lib);
3006#endif
3007 p_qaf->qaf_mod[i].qaf_lib = NULL;
3008 } else {
3009 dlclose(p_qaf->qaf_mod[i].qaf_lib);
3010 p_qaf->qaf_mod[i].qaf_lib = NULL;
3011 }
Harsh Bansal28718c52017-04-20 13:47:12 +05303012 }
3013 }
3014 if (p_qaf->passthrough_out) {
3015 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
3016 (struct audio_stream_out *)(p_qaf->passthrough_out));
3017 p_qaf->passthrough_out = NULL;
3018 }
3019
3020 pthread_mutex_destroy(&p_qaf->lock);
3021 free(p_qaf);
3022 p_qaf = NULL;
3023 }
3024 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05303025}