blob: caf64ee65d3b01ecacb609c7061653731922db4d [file] [log] [blame]
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301/*
Varun B34da7a42017-02-13 16:16:53 +05302 * Copyright (c) 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
34#define ALOGVV ALOGV
35#else
36#define ALOGVV(a...) do { } while(0)
37#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
Varun B34da7a42017-02-13 16:16:53 +053061
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053062#define DD_FRAME_SIZE 1536
Harsh Bansal28718c52017-04-20 13:47:12 +053063#define DDP_FRAME_SIZE DD_FRAME_SIZE
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053064/*
Harsh Bansal28718c52017-04-20 13:47:12 +053065 * DD encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053066 */
67#define DD_ENCODER_OUTPUT_SIZE 2560
68/*
Harsh Bansal28718c52017-04-20 13:47:12 +053069 * DDP encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053070 */
71#define DDP_ENCODER_OUTPUT_SIZE 4608
72
Harsh Bansal28718c52017-04-20 13:47:12 +053073/*********TODO Need to get correct values.*************************/
74
75#define DTS_PCM_OUT_FRAGMENT_SIZE 1024 //samples
76
77#define DTS_FRAME_SIZE 1536
78#define DTSHD_FRAME_SIZE DTS_FRAME_SIZE
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053079/*
Harsh Bansal28718c52017-04-20 13:47:12 +053080 * DTS encoder output size for one frame.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053081 */
Harsh Bansal28718c52017-04-20 13:47:12 +053082#define DTS_ENCODER_OUTPUT_SIZE 2560
83/*
84 * DTSHD encoder output size for one frame.
85 */
86#define DTSHD_ENCODER_OUTPUT_SIZE 4608
87/******************************************************************/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053088
Bharath Gopal01310bb2016-12-05 15:39:32 +053089/*
90 * QAF Latency to process buffers since out_write from primary HAL
91 */
92#define QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY 18
93#define QAF_PCM_OFFLOAD_PROCESSING_LATENCY 48
94
Harsh Bansal28718c52017-04-20 13:47:12 +053095//TODO: Need to handle for DTS
Varun B34da7a42017-02-13 16:16:53 +053096#define QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE 1536
97
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053098#include <stdlib.h>
99#include <pthread.h>
100#include <errno.h>
101#include <dlfcn.h>
102#include <sys/resource.h>
103#include <sys/prctl.h>
104#include <cutils/properties.h>
105#include <cutils/str_parms.h>
106#include <cutils/log.h>
107#include <cutils/atomic.h>
108#include "audio_utils/primitives.h"
109#include "audio_hw.h"
110#include "platform_api.h"
111#include <platform.h>
112#include <system/thread_defs.h>
113#include <cutils/sched_policy.h>
114#include "audio_extn.h"
115#include <qti_audio.h>
116#include "sound/compress_params.h"
117
Harsh Bansal28718c52017-04-20 13:47:12 +0530118//TODO: Need to remove this.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530119#define QAF_OUTPUT_SAMPLING_RATE 48000
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530120
121#ifdef QAF_DUMP_ENABLED
122FILE *fp_output_writer_hdmi = NULL;
123#endif
124
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800125struct qaf_adsp_hdlr_config_state {
126 struct audio_adsp_event event_params;
127 /* For holding client audio_adsp_event payload */
128 uint8_t event_payload[AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN];
129 bool adsp_hdlr_config_valid;
130};
131
Harsh Bansal28718c52017-04-20 13:47:12 +0530132//Types of MM module, currently supported by QAF.
133typedef enum {
134 MS12,
135 DTS_M8,
136 MAX_MM_MODULE_TYPE,
137 INVALID_MM_MODULE
138} mm_module_type;
139
140typedef enum {
141 QAF_OUT_TRANSCODE_PASSTHROUGH = 0, /* Transcode passthrough via MM module*/
142 QAF_OUT_OFFLOAD_MCH, /* Multi-channel PCM offload*/
143 QAF_OUT_OFFLOAD, /* PCM offload */
144
145 MAX_QAF_MODULE_OUT
146} mm_module_output_type;
147
148typedef enum {
149 QAF_IN_MAIN = 0, /* Single PID Main/Primary or Dual-PID stream */
150 QAF_IN_ASSOC, /* Associated/Secondary stream */
151 QAF_IN_PCM, /* PCM stream. */
152
153 MAX_QAF_MODULE_IN
154} mm_module_input_type;
155
156struct qaf_module {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530157 audio_session_handle_t session_handle;
158 void *qaf_lib;
Harsh Bansal28718c52017-04-20 13:47:12 +0530159 int (*qaf_audio_session_open)(audio_session_handle_t* session_handle,
160 void *p_data,
161 void* license_data);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530162 int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
Harsh Bansal28718c52017-04-20 13:47:12 +0530163 int (*qaf_audio_stream_open)(audio_session_handle_t session_handle,
164 audio_stream_handle_t* stream_handle,
165 audio_stream_config_t input_config,
166 audio_devices_t devices,
167 stream_type_t flags);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530168 int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
169 int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
170 int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
171 char* (*qaf_audio_stream_get_param)(audio_stream_handle_t stream_handle, const char* key);
172 char* (*qaf_audio_session_get_param)(audio_session_handle_t handle, const char* key);
173 int (*qaf_audio_stream_start)(audio_stream_handle_t handle);
174 int (*qaf_audio_stream_stop)(audio_stream_handle_t stream_handle);
175 int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
176 int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
177 int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
Harsh Bansal28718c52017-04-20 13:47:12 +0530178 void (*qaf_register_event_callback)(audio_session_handle_t session_handle,
179 void *priv_data,
180 notify_event_callback_t event_callback,
181 audio_event_id_t event_id);
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800182
Harsh Bansal28718c52017-04-20 13:47:12 +0530183 /*Input stream of MM module */
184 struct stream_out *stream_in[MAX_QAF_MODULE_IN];
185 /*Output Stream from MM module */
186 struct stream_out *stream_out[MAX_QAF_MODULE_OUT];
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800187
Harsh Bansal28718c52017-04-20 13:47:12 +0530188 struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_MODULE_IN];
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800189
Harsh Bansal28718c52017-04-20 13:47:12 +0530190 //BT session handle.
Bharath Gopal01310bb2016-12-05 15:39:32 +0530191 void *bt_hdl;
Harsh Bansal28718c52017-04-20 13:47:12 +0530192
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530193 float vol_left;
194 float vol_right;
Harsh Bansal28718c52017-04-20 13:47:12 +0530195 bool is_vol_set;
196 bool drain_received[MAX_QAF_MODULE_IN];
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530197};
198
Harsh Bansal28718c52017-04-20 13:47:12 +0530199struct qaf {
200 struct audio_device *adev;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530201
Harsh Bansal28718c52017-04-20 13:47:12 +0530202 pthread_mutex_t lock;
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800203
Harsh Bansal28718c52017-04-20 13:47:12 +0530204 bool hdmi_connect;
205 int hdmi_sink_channels;
206
207 //Flag to indicate if QAF transcode output stream is enabled from any mm module.
208 bool passthrough_enabled;
209 //Flag to indicate if QAF mch pcm output stream is enabled from any mm module.
210 bool mch_pcm_hdmi_enabled;
211
212 //Flag to indicate if msmd is supported.
213 bool qaf_msmd_enabled;
214
215 //Handle of QAF input stream, which is routed as QAF passthrough.
216 struct stream_out *passthrough_in;
217 //Handle of QAF passthrough stream.
218 struct stream_out *passthrough_out;
219
220 struct qaf_module qaf_mod[MAX_MM_MODULE_TYPE];
221};
222
223static int qaf_out_pause(struct audio_stream_out* stream);
224static int qaf_out_flush(struct audio_stream_out* stream);
225static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type);
226
227//Global handle of QAF. Access to this should be protected by mutex lock.
228static struct qaf *p_qaf = NULL;
229
230/* Gets the pointer to qaf module for the qaf input stream. */
231static struct qaf_module* get_qaf_module_for_input_stream(struct stream_out *out)
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530232{
Harsh Bansal28718c52017-04-20 13:47:12 +0530233 struct qaf_module *qaf_mod = NULL;
234 int i, j;
235 if (!p_qaf) return NULL;
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530236
Harsh Bansal28718c52017-04-20 13:47:12 +0530237 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
238 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
239 if (p_qaf->qaf_mod[i].stream_in[j] == out) {
240 qaf_mod = &(p_qaf->qaf_mod[i]);
241 break;
242 }
243 }
244 }
245
246 return qaf_mod;
Deepak Agarwal1e42b852017-02-11 17:57:04 +0530247}
248
Harsh Bansal28718c52017-04-20 13:47:12 +0530249/* Finds the mm module input stream index for the QAF input stream. */
250static int get_input_stream_index(struct stream_out *out)
251{
252 int index = -1, j;
253 struct qaf_module* qaf_mod = NULL;
254
255 qaf_mod = get_qaf_module_for_input_stream(out);
256 if (!qaf_mod) return index;
257
258 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
259 if (qaf_mod->stream_in[j] == out) {
260 index = j;
261 break;
262 }
263 }
264
265 return index;
266}
267
268/* Finds the right mm module for the QAF input stream format. */
269static mm_module_type get_mm_module_for_format(audio_format_t format)
270{
271 int j;
272
273 DEBUG_MSG("Format 0x%x", format);
274
275 if (format == AUDIO_FORMAT_PCM_16_BIT) {
276 //If dts is not supported then alway support pcm with MS12
277 if (!property_get_bool("audio.qaf.dts_m8", false)) { //TODO: Need to add this property for DTS.
278 return MS12;
279 }
280
281 //If QAF passthrough is active then send the PCM stream to primary HAL.
282 if (!p_qaf->passthrough_out) {
283 /* Iff any stream is active in MS12 module then route PCM stream to it. */
284 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
285 if (p_qaf->qaf_mod[MS12].stream_in[j]) {
286 return MS12;
287 }
288 }
289 }
290 return INVALID_MM_MODULE;
291 }
292
293 switch (format & AUDIO_FORMAT_MAIN_MASK) {
294 case AUDIO_FORMAT_AC3:
295 case AUDIO_FORMAT_E_AC3:
296 case AUDIO_FORMAT_AAC:
297 case AUDIO_FORMAT_AAC_ADTS:
298 case AUDIO_FORMAT_AC4:
299 return MS12;
300 case AUDIO_FORMAT_DTS:
301 case AUDIO_FORMAT_DTS_HD:
302 return DTS_M8;
303 default:
304 return INVALID_MM_MODULE;
305 }
306}
307
308/* Gets the pcm output buffer size(in samples) for the mm module. */
309static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
310{
311 uint32_t pcm_output_buffer_size = 0;
312
313 if (qaf_mod == &p_qaf->qaf_mod[MS12]) {
314 pcm_output_buffer_size = MS12_PCM_OUT_FRAGMENT_SIZE;
315 } else if (qaf_mod == &p_qaf->qaf_mod[DTS_M8]) {
316 pcm_output_buffer_size = DTS_PCM_OUT_FRAGMENT_SIZE;
317 }
318
319 return pcm_output_buffer_size;
320}
321
322/* Acquire Mutex lock on output stream */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530323static void lock_output_stream(struct stream_out *out)
324{
325 pthread_mutex_lock(&out->pre_lock);
326 pthread_mutex_lock(&out->lock);
327 pthread_mutex_unlock(&out->pre_lock);
328}
329
Harsh Bansal28718c52017-04-20 13:47:12 +0530330/* Release Mutex lock on output stream */
331static void unlock_output_stream(struct stream_out *out)
332{
333 pthread_mutex_unlock(&out->lock);
334}
335
336/* Checks if stream can be routed as QAF passthrough or not. */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530337static bool audio_extn_qaf_passthrough_enabled(struct stream_out *out)
338{
Harsh Bansal28718c52017-04-20 13:47:12 +0530339 DEBUG_MSG("Format 0x%x", out->format);
340 bool is_enabled = false;
341
342 if (!p_qaf) return false;
343
344 if ((!property_get_bool("audio.qaf.reencode", false))
345 && property_get_bool("audio.qaf.passthrough", false)) {
346
347 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
348 is_enabled = true;
349 } else if (property_get_bool("audio.offload.passthrough", false)) {
350 switch (out->format) {
351 case AUDIO_FORMAT_AC3:
352 case AUDIO_FORMAT_E_AC3:
353 case AUDIO_FORMAT_DTS:
Ben Romberger1aaaf862017-04-06 17:49:46 -0700354 case AUDIO_FORMAT_DTS_HD:
355 case AUDIO_FORMAT_DOLBY_TRUEHD: {
Harsh Bansal28718c52017-04-20 13:47:12 +0530356 is_enabled = true;
357 break;
358 }
359 default:
360 is_enabled = false;
361 break;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530362 }
363 }
364 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530365
366 return is_enabled;
367}
368
369/*Closes all pcm hdmi output from QAF. */
370static void close_all_pcm_hdmi_output()
371{
372 int i;
373 //Closing all the PCM HDMI output stream from QAF.
374 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
375 if (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]) {
376 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
377 (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH]));
378 p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
379 }
380
381 if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
382 && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
383 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
384 (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
385 p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
386 }
387 }
388
389 p_qaf->mch_pcm_hdmi_enabled = 0;
390}
391
392static void close_all_hdmi_output()
393{
394 int k;
395 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
396 if (p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
397 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
398 (struct audio_stream_out *)(p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
399 p_qaf->qaf_mod[k].stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
400 }
401 }
402 p_qaf->passthrough_enabled = 0;
403
404 close_all_pcm_hdmi_output();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530405}
406
407static int qaf_out_callback(stream_callback_event_t event, void *param __unused, void *cookie)
408{
409 struct stream_out *out = (struct stream_out *)cookie;
410
Ben Rombergerd771a7c2017-02-22 18:05:17 -0800411 out->client_callback(event, NULL, out->client_cookie);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530412 return 0;
413}
414
Harsh Bansal28718c52017-04-20 13:47:12 +0530415/* Creates the QAF passthrough output stream. */
416static int create_qaf_passthrough_stream()
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530417{
Harsh Bansal28718c52017-04-20 13:47:12 +0530418 DEBUG_MSG();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530419
Harsh Bansal28718c52017-04-20 13:47:12 +0530420 int ret = 0, k;
421 struct stream_out *out = p_qaf->passthrough_in;
422
423 if (!out) return -EINVAL;
424
425 pthread_mutex_lock(&p_qaf->lock);
426 lock_output_stream(out);
427
428 //Creating QAF passthrough output stream.
429 if (NULL == p_qaf->passthrough_out) {
430 audio_output_flags_t flags;
431 struct audio_config config;
432 audio_devices_t devices;
433
434 config.sample_rate = config.offload_info.sample_rate = out->sample_rate;
435 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
436 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
437 config.offload_info.format = out->format;
438 config.offload_info.bit_width = out->bit_width;
439 config.format = out->format;
440 config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
441
442 //Device is copied from the QAF passthrough input stream.
443 devices = out->devices;
444 flags = out->flags;
445
446 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
447 QAF_DEFAULT_PASSTHROUGH_HANDLE,
448 devices,
449 flags,
450 &config,
451 (struct audio_stream_out **)&(p_qaf->passthrough_out),
452 NULL);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530453 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530454 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
455 unlock_output_stream(out);
456 return ret;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530457 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530458 p_qaf->passthrough_in = out;
459 p_qaf->passthrough_out->stream.set_callback((struct audio_stream_out *)p_qaf->passthrough_out,
460 (stream_callback_t) qaf_out_callback, out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530461 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530462
463 unlock_output_stream(out);
464
465 //Since QAF-Passthrough is created, close other HDMI outputs.
466 close_all_hdmi_output();
467
468 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530469 return ret;
470}
471
Harsh Bansal28718c52017-04-20 13:47:12 +0530472/* Closes the QAF passthrough output stream. */
473static void close_qaf_passthrough_stream()
474{
475 if (p_qaf->passthrough_out != NULL) { //QAF pasthroug is enabled. Close it.
476 pthread_mutex_lock(&p_qaf->lock);
477 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
478 (struct audio_stream_out *)(p_qaf->passthrough_out));
479 p_qaf->passthrough_out = NULL;
480 pthread_mutex_unlock(&p_qaf->lock);
481
482 if (p_qaf->passthrough_in->qaf_stream_handle) {
483 qaf_out_pause((struct audio_stream_out*)p_qaf->passthrough_in);
484 qaf_out_flush((struct audio_stream_out*)p_qaf->passthrough_in);
485 qaf_out_drain((struct audio_stream_out*)p_qaf->passthrough_in,
486 (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
487 }
488 }
489}
490
491/* Sends a command to output stream offload thread. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530492static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
493{
Harsh Bansal28718c52017-04-20 13:47:12 +0530494 DEBUG_MSG("command is %d", command);
495
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530496 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
497
498 if (!cmd) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530499 ERROR_MSG("failed to allocate mem for command 0x%x", command);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530500 return -ENOMEM;
501 }
502
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530503 cmd->cmd = command;
Harsh Bansal28718c52017-04-20 13:47:12 +0530504
505 lock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530506 list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
507 pthread_cond_signal(&out->qaf_offload_cond);
Harsh Bansal28718c52017-04-20 13:47:12 +0530508 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530509 return 0;
510}
511
Harsh Bansal28718c52017-04-20 13:47:12 +0530512/* Stops a QAF module stream.*/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530513static int audio_extn_qaf_stream_stop(struct stream_out *out)
514{
Harsh Bansal28718c52017-04-20 13:47:12 +0530515 int ret = 0;
516 DEBUG_MSG("Output Stream 0x%x", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530517
Harsh Bansal28718c52017-04-20 13:47:12 +0530518 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
519 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_stop)) {
520 return ret;
521 }
522
523 if (out->qaf_stream_handle) {
524 ret = qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
525 }
526
527 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530528}
529
Harsh Bansal28718c52017-04-20 13:47:12 +0530530/* Puts a QAF module stream in standby. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530531static int qaf_out_standby(struct audio_stream *stream)
532{
533 struct stream_out *out = (struct stream_out *)stream;
534 int status = 0;
535
536 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
537 stream, out->usecase, use_case_table[out->usecase]);
538
539 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +0530540
541 //If QAF passthrough is active then block standby on all the input streams of QAF mm modules.
542 if (p_qaf->passthrough_out) {
543 //If standby is received on QAF passthrough stream then forward it to primary HAL.
544 if (p_qaf->passthrough_in == out) {
545 status = p_qaf->passthrough_out->stream.common.standby(
546 (struct audio_stream *)p_qaf->passthrough_out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530547 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530548 } else {
549 //If QAF passthrough stream is not active then stop the QAF module stream.
550 status = audio_extn_qaf_stream_stop(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530551 }
552
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530553 if (!out->standby) {
554 out->standby = true;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530555 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530556
557 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530558 return status;
559}
560
Harsh Bansal28718c52017-04-20 13:47:12 +0530561/* Sets the volume to PCM output stream. */
562static int qaf_out_set_volume(struct audio_stream_out *stream, float left, float right)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530563{
564 int ret = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530565 struct stream_out *out = (struct stream_out *)stream;
566 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530567
Harsh Bansal28718c52017-04-20 13:47:12 +0530568 DEBUG_MSG("Left %f, Right %f", left, right);
569
570 qaf_mod = get_qaf_module_for_input_stream(out);
571 if (!qaf_mod) {
572 return -EINVAL;
573 }
574
575 pthread_mutex_lock(&p_qaf->lock);
576 qaf_mod->vol_left = left;
577 qaf_mod->vol_right = right;
578 qaf_mod->is_vol_set = true;
579 pthread_mutex_unlock(&p_qaf->lock);
580
581 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL) {
582 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
583 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], left, right);
584 }
585
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530586 return ret;
587}
588
Harsh Bansal28718c52017-04-20 13:47:12 +0530589/* Starts a QAF module stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530590static int qaf_stream_start(struct stream_out *out)
591{
Harsh Bansal28718c52017-04-20 13:47:12 +0530592 int ret = -EINVAL;
593 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530594
Harsh Bansal28718c52017-04-20 13:47:12 +0530595 DEBUG_MSG("Output Stream = %p", out);
596
597 qaf_mod = get_qaf_module_for_input_stream(out);
598 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_start)) {
599 return -EINVAL;
600 }
601
602 if (out->qaf_stream_handle) {
603 ret = qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
604 }
605
606 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530607}
608
609static int qaf_start_output_stream(struct stream_out *out)
610{
611 int ret = 0;
612 struct audio_device *adev = out->dev;
613 int snd_card_status = get_snd_card_state(adev);
614
615 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
616 ret = -EINVAL;
617 usleep(50000);
618 return ret;
619 }
620
621 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
622 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
623 out->devices);
624
625 if (SND_CARD_STATE_OFFLINE == snd_card_status) {
626 ALOGE("%s: sound card is not active/SSR returning error", __func__);
627 ret = -EIO;
628 usleep(50000);
629 return ret;
630 }
631
632 return qaf_stream_start(out);
633}
634
Harsh Bansal28718c52017-04-20 13:47:12 +0530635/* Sends input buffer to the QAF MM module. */
636static int qaf_module_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
637{
638 int ret = -EINVAL;
639 struct qaf_module *qaf_mod = NULL;
640 DEBUG_MSG("bytes = %d [%p]", bytes, out->qaf_stream_handle);
641
642 qaf_mod = get_qaf_module_for_input_stream(out);
643 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_write)) {
644 return ret;
645 }
646
647 if (out->qaf_stream_handle) {
648 ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
649 }
650 return ret;
651}
652
653/* Writes buffer to QAF input stream. */
654static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer, size_t bytes)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530655{
656 struct stream_out *out = (struct stream_out *)stream;
657 struct audio_device *adev = out->dev;
658 ssize_t ret = 0;
659
Harsh Bansal28718c52017-04-20 13:47:12 +0530660 DEBUG_MSG("bytes = %d, usecase[%d] and flags[%x] for handle[%p]",
661 (int)bytes, out->usecase, out->flags, out);
662
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530663 lock_output_stream(out);
664
Harsh Bansal28718c52017-04-20 13:47:12 +0530665 // If QAF passthrough is active then block writing data to QAF mm module.
666 if (p_qaf->passthrough_out) {
667 //If write is received for the QAF passthrough stream then send the buffer to primary HAL.
668 if (p_qaf->passthrough_in == out) {
669 ret = p_qaf->passthrough_out->stream.write(
670 (struct audio_stream_out *)(p_qaf->passthrough_out),
671 buffer,
672 bytes);
673 if (ret > 0) out->standby = false;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530674 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530675 unlock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530676 return ret;
Harsh Bansal28718c52017-04-20 13:47:12 +0530677 } else if (out->standby) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530678 pthread_mutex_lock(&adev->lock);
679 ret = qaf_start_output_stream(out);
680 pthread_mutex_unlock(&adev->lock);
Harsh Bansal28718c52017-04-20 13:47:12 +0530681 if (ret == 0) {
682 out->standby = false;
683 } else {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530684 goto exit;
685 }
686 }
687
Harsh Bansal28718c52017-04-20 13:47:12 +0530688 if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530689 audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
690 adev->is_channel_status_set = true;
691 }
692
Harsh Bansal28718c52017-04-20 13:47:12 +0530693 ret = qaf_module_write_input_buffer(out, buffer, bytes);
694 DEBUG_MSG("ret [%d]", (int)ret);
695
696 if (ret >= 0) {
697 bytes = ret;
698 out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530699 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530700
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530701
702exit:
Harsh Bansal28718c52017-04-20 13:47:12 +0530703 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530704
705 if (ret < 0) {
706 if (ret == -EAGAIN) {
Harsh Bansal28718c52017-04-20 13:47:12 +0530707 DEBUG_MSG("No space available in mm module, post msg to cb thread");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530708 ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530709 bytes = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530710 } else if (ret == -ENOMEM || ret == -EPERM) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530711 if (out->pcm)
Harsh Bansal28718c52017-04-20 13:47:12 +0530712 ERROR_MSG("error %d, %s", (int)ret, pcm_get_error(out->pcm));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530713 qaf_out_standby(&out->stream.common);
Harsh Bansal28718c52017-04-20 13:47:12 +0530714 usleep(bytes * 1000000
715 / audio_stream_out_frame_size(stream)
716 / out->stream.common.get_sample_rate(&out->stream.common));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530717 }
718 }
719 return bytes;
720}
721
Harsh Bansal28718c52017-04-20 13:47:12 +0530722/* Gets PCM offload buffer size for QAF module output. */
723static uint32_t qaf_get_pcm_offload_buffer_size(struct qaf_module *qaf_mod,
724 audio_offload_info_t* info)
Varun B34da7a42017-02-13 16:16:53 +0530725{
Harsh Bansal28718c52017-04-20 13:47:12 +0530726 uint32_t samples_per_frame = get_pcm_output_buffer_size_samples(qaf_mod);
Varun B34da7a42017-02-13 16:16:53 +0530727 uint32_t fragment_size = 0;
Varun B34da7a42017-02-13 16:16:53 +0530728
Harsh Bansal28718c52017-04-20 13:47:12 +0530729 fragment_size = (samples_per_frame * (info->bit_width >> 3) * popcount(info->channel_mask));
730
731 if (fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
Varun B34da7a42017-02-13 16:16:53 +0530732 fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
Harsh Bansal28718c52017-04-20 13:47:12 +0530733 else if (fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
Varun B34da7a42017-02-13 16:16:53 +0530734 fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
Harsh Bansal28718c52017-04-20 13:47:12 +0530735
Varun B34da7a42017-02-13 16:16:53 +0530736 // To have same PCM samples for all channels, the buffer size requires to
737 // be multiple of (number of channels * bytes per sample)
738 // For writes to succeed, the buffer must be written at address which is multiple of 32
Harsh Bansal28718c52017-04-20 13:47:12 +0530739 fragment_size = ALIGN(fragment_size,
740 ((info->bit_width >> 3) * popcount(info->channel_mask) * 32));
Varun B34da7a42017-02-13 16:16:53 +0530741
742 ALOGI("Qaf PCM offload Fragment size to %d bytes", fragment_size);
743
744 return fragment_size;
745}
746
Harsh Bansal28718c52017-04-20 13:47:12 +0530747/* Gets buffer latency in samples. */
748static int get_buffer_latency(struct stream_out *out, uint32_t buffer_size, uint32_t *latency)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530749{
Harsh Bansal28718c52017-04-20 13:47:12 +0530750 unsigned long int samples_in_one_encoded_frame;
751 unsigned long int size_of_one_encoded_frame;
752
753 switch (out->format) {
754 case AUDIO_FORMAT_AC3:
755 samples_in_one_encoded_frame = DD_FRAME_SIZE;
756 size_of_one_encoded_frame = DD_ENCODER_OUTPUT_SIZE;
757 break;
758 case AUDIO_FORMAT_E_AC3:
759 samples_in_one_encoded_frame = DDP_FRAME_SIZE;
760 size_of_one_encoded_frame = DDP_ENCODER_OUTPUT_SIZE;
761 break;
762 case AUDIO_FORMAT_DTS:
763 samples_in_one_encoded_frame = DTS_FRAME_SIZE;
764 size_of_one_encoded_frame = DTS_ENCODER_OUTPUT_SIZE;
765 break;
766 case AUDIO_FORMAT_DTS_HD:
767 samples_in_one_encoded_frame = DTSHD_FRAME_SIZE;
768 size_of_one_encoded_frame = DTSHD_ENCODER_OUTPUT_SIZE;
769 break;
770 case AUDIO_FORMAT_PCM_16_BIT:
771 samples_in_one_encoded_frame = 1;
772 size_of_one_encoded_frame = ((out->bit_width) >> 3) * popcount(out->channel_mask);
773 break;
774 default:
775 *latency = 0;
776 return (-EINVAL);
777 }
778
779 *latency = ((buffer_size * samples_in_one_encoded_frame) / size_of_one_encoded_frame);
780 return 0;
781}
782
783/* Returns the number of frames rendered to outside observer. */
784static int qaf_get_rendered_frames(struct stream_out *out, uint64_t *frames)
785{
786 int ret = 0, i;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530787 struct str_parms *parms;
788 int value = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530789 int module_latency = 0;
790 uint32_t kernel_latency = 0;
791 uint32_t dsp_latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530792 int signed_frames = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530793 char* kvpairs = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +0530794 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530795
Harsh Bansal28718c52017-04-20 13:47:12 +0530796 DEBUG_MSG("Output Format %d", out->format);
797
798 qaf_mod = get_qaf_module_for_input_stream(out);
799 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_get_param)) {
800 return -EINVAL;
801 }
802
803 //Get MM module latency.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530804 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "get_latency");
805 if (kvpairs) {
806 parms = str_parms_create_str(kvpairs);
Harsh Bansal28718c52017-04-20 13:47:12 +0530807 ret = str_parms_get_int(parms, "get_latency", &module_latency);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530808 if (ret >= 0) {
809 str_parms_destroy(parms);
810 parms = NULL;
811 }
812 free(kvpairs);
813 kvpairs = NULL;
814 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530815
816 //Get kernel Latency
817 for (i = MAX_QAF_MODULE_OUT - 1; i >= 0; i--) {
818 if (qaf_mod->stream_out[i] == NULL) {
819 continue;
820 } else {
821 unsigned int num_fragments = qaf_mod->stream_out[i]->compr_config.fragments;
822 uint32_t fragment_size = qaf_mod->stream_out[i]->compr_config.fragment_size;
823 uint32_t kernel_buffer_size = num_fragments * fragment_size;
824 get_buffer_latency(qaf_mod->stream_out[i], kernel_buffer_size, &kernel_latency);
825 break;
826 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530827 }
828
Harsh Bansal28718c52017-04-20 13:47:12 +0530829 //Get DSP latency
830 if ((qaf_mod->stream_out[QAF_OUT_OFFLOAD] != NULL)
831 || (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] != NULL)) {
832 unsigned int sample_rate = 0;
833
834 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
835 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
836 else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
837 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
838
839 audio_usecase_t platform_latency =
840 platform_render_latency(qaf_mod->stream_out[QAF_OUT_OFFLOAD]->usecase);
841 dsp_latency = (platform_latency * sample_rate) / 1000000LL;
842 } else if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] != NULL) {
843 unsigned int sample_rate = 0;
844
845 sample_rate = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->sample_rate; //TODO: How this sample rate can be used?
846 dsp_latency = (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * sample_rate) / 1000;
847 }
848
849 // MM Module Latency + Kernel Latency + DSP Latency
850 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
851 out->platform_latency = module_latency + audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl);
852 } else {
853 out->platform_latency = (uint32_t)module_latency + kernel_latency + dsp_latency;
854 }
855
856 if (out->format & AUDIO_FORMAT_PCM_16_BIT) {
857 *frames = 0;
858 signed_frames = out->written - out->platform_latency;
859 // It would be unusual for this value to be negative, but check just in case ...
860 if (signed_frames >= 0) {
861 *frames = signed_frames;
862 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530863 } else if (qaf_mod->qaf_audio_stream_get_param) {
864 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
865 if (kvpairs) {
866 parms = str_parms_create_str(kvpairs);
867 ret = str_parms_get_int(parms, "position", &value);
868 if (ret >= 0) {
869 *frames = value;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530870 signed_frames = value - out->platform_latency;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530871 // It would be unusual for this value to be negative, but check just in case ...
872 if (signed_frames >= 0) {
873 *frames = signed_frames;
874 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530875 }
876 str_parms_destroy(parms);
877 }
878 } else {
879 ret = -EINVAL;
880 }
Harsh Bansal28718c52017-04-20 13:47:12 +0530881
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530882 return ret;
883}
884
885static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
Harsh Bansal28718c52017-04-20 13:47:12 +0530886 uint64_t *frames,
887 struct timespec *timestamp)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530888{
889 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +0530890 int ret = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530891
Harsh Bansal28718c52017-04-20 13:47:12 +0530892 DEBUG_MSG("Output Stream %p", stream);
893
894 //If QAF passthorugh output stream is active.
895 if (p_qaf->passthrough_out) {
896 if (p_qaf->passthrough_in == out) {
897 //If api is called for QAF passthorugh stream then call the primary HAL api to get the position.
898 pthread_mutex_lock(&p_qaf->lock);
899 ret = p_qaf->passthrough_out->stream.get_presentation_position(
900 (struct audio_stream_out *)p_qaf->passthrough_out,
901 frames,
902 timestamp);
903 pthread_mutex_unlock(&p_qaf->lock);
904 } else {
905 //If api is called for other stream then return zero frames.
906 *frames = 0;
907 clock_gettime(CLOCK_MONOTONIC, timestamp);
908 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530909 return ret;
910 }
911
Harsh Bansal28718c52017-04-20 13:47:12 +0530912 ret = qaf_get_rendered_frames(out, frames);
913 clock_gettime(CLOCK_MONOTONIC, timestamp);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530914
915 return ret;
916}
917
Harsh Bansal28718c52017-04-20 13:47:12 +0530918/* Pause the QAF module input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530919static int qaf_stream_pause(struct stream_out *out)
920{
Harsh Bansal28718c52017-04-20 13:47:12 +0530921 struct qaf_module *qaf_mod = NULL;
922 int ret = -EINVAL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530923
Harsh Bansal28718c52017-04-20 13:47:12 +0530924 qaf_mod = get_qaf_module_for_input_stream(out);
925 if (!qaf_mod || !qaf_mod->qaf_audio_stream_pause) {
926 return -EINVAL;
927 }
928
929 if (out->qaf_stream_handle)
930 ret = qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
931
932 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530933}
934
Harsh Bansal28718c52017-04-20 13:47:12 +0530935/* Pause a QAF input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530936static int qaf_out_pause(struct audio_stream_out* stream)
937{
938 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +0530939 int status = 0;
940 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530941
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530942 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +0530943
944 //If QAF passthrough is enabled then block the pause on module stream.
945 if (p_qaf->passthrough_out) {
946 pthread_mutex_lock(&p_qaf->lock);
947 //If pause is received for QAF passthorugh stream then call the primary HAL api.
948 if (p_qaf->passthrough_in == out) {
949 status = p_qaf->passthrough_out->stream.pause(
950 (struct audio_stream_out *)p_qaf->passthrough_out);
951 out->offload_state = OFFLOAD_STATE_PAUSED;
952 }
953 pthread_mutex_unlock(&p_qaf->lock);
954 } else {
955 //Pause the module input stream.
956 status = qaf_stream_pause(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530957 }
958
Harsh Bansal28718c52017-04-20 13:47:12 +0530959 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530960 return status;
961}
962
Harsh Bansal28718c52017-04-20 13:47:12 +0530963/* Drains a qaf input stream. */
964static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530965{
966 struct stream_out *out = (struct stream_out *)stream;
967 int status = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +0530968 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530969
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530970 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +0530971
972 //If QAF passthrough is enabled then block the drain on module stream.
973 if (p_qaf->passthrough_out) {
974 pthread_mutex_lock(&p_qaf->lock);
975 //If drain is received for QAF passthorugh stream then call the primary HAL api.
976 if (p_qaf->passthrough_in == out) {
977 status = p_qaf->passthrough_out->stream.drain(
978 (struct audio_stream_out *)p_qaf->passthrough_out, type);
979 }
980 pthread_mutex_unlock(&p_qaf->lock);
981 } else {
982 //Drain the module input stream.
983 /* Stream stop will trigger EOS and on EOS_EVENT received
984 from callback DRAIN_READY command is sent */
985 status = audio_extn_qaf_stream_stop(out);
986
987 if (status == 0) {
988 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
989 int index = get_input_stream_index(out);
990 if (qaf_mod && index >= 0) qaf_mod->drain_received[index] = true;
991 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530992 }
993
Harsh Bansal28718c52017-04-20 13:47:12 +0530994 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530995 return status;
996}
997
Harsh Bansal28718c52017-04-20 13:47:12 +0530998/* Flush the QAF module input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530999static int audio_extn_qaf_stream_flush(struct stream_out *out)
1000{
Harsh Bansal28718c52017-04-20 13:47:12 +05301001 DEBUG_MSG("Output Stream %p", out);
1002 int ret = -EINVAL;
1003 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301004
Harsh Bansal28718c52017-04-20 13:47:12 +05301005 qaf_mod = get_qaf_module_for_input_stream(out);
1006 if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_flush)) {
1007 return -EINVAL;
1008 }
1009
1010 if (out->qaf_stream_handle)
1011 ret = qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
1012
1013 return ret;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301014}
1015
Harsh Bansal28718c52017-04-20 13:47:12 +05301016/* Flush the QAF input stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301017static int qaf_out_flush(struct audio_stream_out* stream)
1018{
1019 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05301020 int status = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301021
Harsh Bansal28718c52017-04-20 13:47:12 +05301022 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301023 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301024
1025 //If QAF passthrough is active then block the flush on module input streams.
1026 if (p_qaf->passthrough_out) {
1027 pthread_mutex_lock(&p_qaf->lock);
1028 //If flush is received for the QAF passthrough stream then call the primary HAL api.
1029 if (p_qaf->passthrough_in == out) {
1030 status = p_qaf->passthrough_out->stream.flush(
1031 (struct audio_stream_out *)p_qaf->passthrough_out);
1032 out->offload_state = OFFLOAD_STATE_IDLE;
1033 }
1034 pthread_mutex_unlock(&p_qaf->lock);
1035 } else {
1036 //Flush the module input stream.
1037 status = audio_extn_qaf_stream_flush(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301038 }
1039
Harsh Bansal28718c52017-04-20 13:47:12 +05301040 unlock_output_stream(out);
1041 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301042 return status;
1043}
1044
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301045static uint32_t qaf_out_get_latency(const struct audio_stream_out *stream)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301046{
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301047 struct stream_out *out = (struct stream_out *)stream;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301048 uint32_t latency = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +05301049 struct qaf_module *qaf_mod = NULL;
1050 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301051
Harsh Bansal28718c52017-04-20 13:47:12 +05301052 qaf_mod = get_qaf_module_for_input_stream(out);
1053 if (!qaf_mod) {
1054 return 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301055 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301056
Harsh Bansal28718c52017-04-20 13:47:12 +05301057 //If QAF passthrough is active then block the get latency on module input streams.
1058 if (p_qaf->passthrough_out) {
1059 pthread_mutex_lock(&p_qaf->lock);
1060 //If get latency is called for the QAF passthrough stream then call the primary HAL api.
1061 if (p_qaf->passthrough_in == out) {
1062 latency = p_qaf->passthrough_out->stream.get_latency(
1063 (struct audio_stream_out *)p_qaf->passthrough_out);
1064 }
1065 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301066 } else {
Bharath Gopal01310bb2016-12-05 15:39:32 +05301067 if (is_offload_usecase(out->usecase)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301068 latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301069 } else {
Harsh Bansal28718c52017-04-20 13:47:12 +05301070 uint32_t sample_rate = 0;
1071 latency = QAF_MODULE_PCM_INPUT_BUFFER_LATENCY; //Input latency
1072
1073 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD])
1074 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->sample_rate;
1075 else if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])
1076 sample_rate = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->sample_rate;
1077
1078 if (sample_rate) {
1079 latency += (get_pcm_output_buffer_size_samples(qaf_mod) * 1000) / out->sample_rate;
1080 }
1081 }
1082
1083 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
1084 if (is_offload_usecase(out->usecase)) {
1085 latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
1086 QAF_COMPRESS_OFFLOAD_PROCESSING_LATENCY;
1087 } else {
1088 latency = audio_extn_bt_hal_get_latency(qaf_mod->bt_hdl) +
1089 QAF_PCM_OFFLOAD_PROCESSING_LATENCY;
1090 }
Bharath Gopal01310bb2016-12-05 15:39:32 +05301091 }
1092 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301093
1094 DEBUG_MSG("Latency %d", latency);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301095 return latency;
1096}
1097
Harsh Bansal28718c52017-04-20 13:47:12 +05301098static bool check_and_get_compressed_device_format(int device, int *format)
1099{
1100 switch (device) {
1101 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD):
1102 *format = AUDIO_FORMAT_AC3;
1103 return true;
1104 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP):
1105 *format = AUDIO_FORMAT_E_AC3;
1106 return true;
1107 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS):
1108 *format = AUDIO_FORMAT_DTS;
1109 return true;
1110 case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS_HD):
1111 *format = AUDIO_FORMAT_DTS_HD;
1112 return true;
1113 default:
1114 return false;
1115 }
1116}
1117
1118/* Call back function for mm module. */
1119static void notify_event_callback(audio_session_handle_t session_handle /*__unused*/,
1120 void *prv_data,
1121 void *buf,
1122 audio_event_id_t event_id,
1123 int size,
1124 int device) //TODO: add media format as well.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301125{
1126
Harsh Bansal28718c52017-04-20 13:47:12 +05301127 /*
1128 For SPKR:
1129 1. Open pcm device if device_id passed to it SPKR and write the data to
1130 pcm device
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301131
Harsh Bansal28718c52017-04-20 13:47:12 +05301132 For HDMI
1133 1.Open compress device for HDMI(PCM or AC3) based on current hdmi o/p format and write
1134 data to the HDMI device.
1135 */
1136 int ret, i;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301137 audio_output_flags_t flags;
Harsh Bansal28718c52017-04-20 13:47:12 +05301138 struct qaf_module* qaf_mod = (struct qaf_module*)prv_data;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301139 struct audio_stream_out *bt_stream = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301140 int format;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301141
Harsh Bansal28718c52017-04-20 13:47:12 +05301142 DEBUG_MSG("Device 0x%X, Event = 0x%X", device, event_id);
1143 pthread_mutex_lock(&p_qaf->lock);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301144
1145 if (event_id == AUDIO_DATA_EVENT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301146 DEBUG_MSG("Device id 0x%X, bytes to write %d", device, size);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301147
Harsh Bansal28718c52017-04-20 13:47:12 +05301148 if (p_qaf->passthrough_out != NULL) {
1149 //If QAF passthrough is active then all the module output will be dropped.
1150 pthread_mutex_unlock(&p_qaf->lock);
1151 DEBUG_MSG("QAF-PSTH is active, DROPPING DATA!");
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301152 return;
Harsh Bansal28718c52017-04-20 13:47:12 +05301153 }
1154
1155 if (check_and_get_compressed_device_format(device, &format)) {
1156 /*
1157 * CASE 1: Transcoded output of mm module.
1158 * If HDMI is not connected then drop the data.
1159 * Only one HDMI output can be supported from all the mm modules of QAF.
1160 * Multi-Channel PCM HDMI output streams will be closed from all the mm modules.
1161 * If transcoded output of other module is already enabled then this data will be dropped.
1162 */
1163
1164 if (!p_qaf->hdmi_connect) {
1165 DEBUG_MSG("HDMI not connected, DROPPING DATA!");
1166 pthread_mutex_unlock(&p_qaf->lock);
1167 return;
1168 }
1169
1170 //Closing all the PCM HDMI output stream from QAF.
1171 close_all_pcm_hdmi_output();
1172
1173 if (!p_qaf->passthrough_enabled
1174 && !(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH])) {
1175
1176 struct audio_config config;
1177 audio_devices_t devices;
1178
1179 //TODO: need to update the actual sample rate.
1180 config.sample_rate = config.offload_info.sample_rate =
1181 QAF_OUTPUT_SAMPLING_RATE;
1182 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1183 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
1184 config.format = config.offload_info.format = format;
1185 //TODO: need to update the actual bit width.
1186 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
1187 //TODO: What is the relevance of num of channels.
1188 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
1189
1190 flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING
1191 | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
1192 | AUDIO_OUTPUT_FLAG_DIRECT);
1193 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
1194
1195 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1196 QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE,
1197 devices,
1198 flags,
1199 &config,
1200 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]),
1201 NULL);
1202 if (ret < 0) {
1203 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1204 pthread_mutex_unlock(&p_qaf->lock);
1205 return;
1206 }
1207
1208 if (format & AUDIO_COMPRESSED_OUT_DDP) {
1209 qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragment_size =
1210 COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE;
1211 }
1212 qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragments =
1213 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1214
1215 p_qaf->passthrough_enabled = true;
1216 }
1217
1218 if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
1219 ret = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
1220 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH],
1221 buf,
1222 size);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301223 }
1224 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301225 else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1226 && (p_qaf->hdmi_connect)
1227 && (p_qaf->hdmi_sink_channels > 2)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301228
Harsh Bansal28718c52017-04-20 13:47:12 +05301229 /* CASE 2: Multi-Channel PCM output to HDMI.
1230 * If any other HDMI output is already enabled then this has to be dropped.
1231 */
1232 bool create_mch_out_stream = false;
1233
1234 if (p_qaf->passthrough_enabled) {
1235 //Closing all the multi-Channel PCM HDMI output stream from QAF.
1236 close_all_pcm_hdmi_output();
1237
1238 //If passthrough is active then pcm hdmi output has to be dropped.
1239 pthread_mutex_unlock(&p_qaf->lock);
1240 DEBUG_MSG("Compressed passthrough enabled, DROPPING DATA!");
1241 return;
1242 }
1243
1244 if (!p_qaf->mch_pcm_hdmi_enabled && !(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301245 struct audio_config config;
1246 audio_devices_t devices;
1247
Harsh Bansal28718c52017-04-20 13:47:12 +05301248 //TODO: need to update the actual sample rate.
Varun B34da7a42017-02-13 16:16:53 +05301249 config.sample_rate = config.offload_info.sample_rate =
Harsh Bansal28718c52017-04-20 13:47:12 +05301250 QAF_OUTPUT_SAMPLING_RATE;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301251 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1252 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
Harsh Bansal28718c52017-04-20 13:47:12 +05301253 config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
1254 //TODO: need to update the actual bit width.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301255 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301256
Harsh Bansal28718c52017-04-20 13:47:12 +05301257 if (p_qaf->hdmi_sink_channels == 8) {
Varun B34da7a42017-02-13 16:16:53 +05301258 config.offload_info.channel_mask = config.channel_mask =
Harsh Bansal28718c52017-04-20 13:47:12 +05301259 AUDIO_CHANNEL_OUT_7POINT1;
1260 } else if (p_qaf->hdmi_sink_channels == 6) {
Varun B34da7a42017-02-13 16:16:53 +05301261 config.offload_info.channel_mask = config.channel_mask =
Harsh Bansal28718c52017-04-20 13:47:12 +05301262 AUDIO_CHANNEL_OUT_5POINT1;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301263 } else {
Varun B34da7a42017-02-13 16:16:53 +05301264 config.offload_info.channel_mask = config.channel_mask =
Harsh Bansal28718c52017-04-20 13:47:12 +05301265 AUDIO_CHANNEL_OUT_STEREO;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301266 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301267
Harsh Bansal28718c52017-04-20 13:47:12 +05301268 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
1269 flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
1270
1271 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1272 QAF_DEFAULT_COMPR_AUDIO_HANDLE,
1273 devices,
1274 flags,
1275 &config,
1276 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]),
1277 NULL);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301278 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301279 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1280 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301281 return;
1282 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001283
Harsh Bansal28718c52017-04-20 13:47:12 +05301284 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
1285 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1286 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragment_size =
1287 qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
1288
1289 p_qaf->mch_pcm_hdmi_enabled = true;
1290
1291 if (qaf_mod->stream_in[QAF_IN_MAIN]
1292 && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
1293
1294 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
1295 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1296 qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
1297 qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
1298 } else if (qaf_mod->stream_in[QAF_IN_PCM]
1299 && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
1300
1301 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.set_callback(
1302 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1303 qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
1304 qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
1305 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001306
1307 int index = -1;
1308 if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301309 index = (int) QAF_IN_MAIN;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001310 else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301311 index = (int) QAF_IN_PCM;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001312
Harsh Bansal28718c52017-04-20 13:47:12 +05301313 if (index >= 0) {
1314 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->standby)
1315 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
1316 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], NULL, 0);
1317
1318 lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001319 ret = audio_extn_out_set_param_data(
Harsh Bansal28718c52017-04-20 13:47:12 +05301320 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1321 AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
1322 (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
1323 unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001324
1325 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301326 }
1327
Harsh Bansal28718c52017-04-20 13:47:12 +05301328 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
1329 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
1330 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
1331 buf,
1332 size);
Varun B34da7a42017-02-13 16:16:53 +05301333 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301334 }
1335 else {
1336 /* CASE 3: PCM output.
1337 */
Bharath Gopal01310bb2016-12-05 15:39:32 +05301338 bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
1339 if (bt_stream != NULL) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301340 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
1341 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1342 (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
1343 qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
Bharath Gopal01310bb2016-12-05 15:39:32 +05301344 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301345
Harsh Bansal28718c52017-04-20 13:47:12 +05301346 audio_extn_bt_hal_out_write(p_qaf->bt_hdl, buf, size);
1347 } else if (NULL == qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301348 struct audio_config config;
1349 audio_devices_t devices;
1350
Harsh Bansal28718c52017-04-20 13:47:12 +05301351 //TODO: need to update the actual sample rate.
Varun B34da7a42017-02-13 16:16:53 +05301352 config.sample_rate = config.offload_info.sample_rate =
Harsh Bansal28718c52017-04-20 13:47:12 +05301353 QAF_OUTPUT_SAMPLING_RATE;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301354 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1355 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
Harsh Bansal28718c52017-04-20 13:47:12 +05301356 config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
1357 //TODO: need to update the actual bit width.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301358 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Harsh Bansal28718c52017-04-20 13:47:12 +05301359 //TODO: need to update the actual num channels.
1360 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301361
Harsh Bansal28718c52017-04-20 13:47:12 +05301362 if (qaf_mod->stream_in[QAF_IN_MAIN])
1363 devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
1364 else
1365 devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
1366
1367 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
1368 if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
1369 if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1370 devices ^= AUDIO_DEVICE_OUT_AUX_DIGITAL;
1371 }
1372 if (devices == 0) {
1373 devices = device;
1374 }
1375
1376 flags = (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001377
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301378 /* TODO:: Need to Propagate errors to framework */
Harsh Bansal28718c52017-04-20 13:47:12 +05301379 ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
1380 QAF_DEFAULT_COMPR_AUDIO_HANDLE,
1381 devices,
1382 flags,
1383 &config,
1384 (struct audio_stream_out **)&(qaf_mod->stream_out[QAF_OUT_OFFLOAD]),
1385 NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301386 if (ret < 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301387 ERROR_MSG("adev_open_output_stream failed with ret = %d!", ret);
1388 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301389 return;
1390 }
Deepak Agarwal1e42b852017-02-11 17:57:04 +05301391
Harsh Bansal28718c52017-04-20 13:47:12 +05301392 if (qaf_mod->stream_in[QAF_IN_MAIN]
1393 && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001394
Harsh Bansal28718c52017-04-20 13:47:12 +05301395 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
1396 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1397 qaf_mod->stream_in[QAF_IN_MAIN]->client_callback,
1398 qaf_mod->stream_in[QAF_IN_MAIN]->client_cookie);
1399 } else if (qaf_mod->stream_in[QAF_IN_PCM]
1400 && qaf_mod->stream_in[QAF_IN_PCM]->client_callback != NULL) {
1401
1402 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_callback(
1403 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1404 qaf_mod->stream_in[QAF_IN_PCM]->client_callback,
1405 qaf_mod->stream_in[QAF_IN_PCM]->client_cookie);
1406 }
1407
1408 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragments =
1409 COMPRESS_OFFLOAD_NUM_FRAGMENTS;
1410 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->compr_config.fragment_size =
1411 qaf_get_pcm_offload_buffer_size(qaf_mod, &config.offload_info);
1412
1413 if (qaf_mod->is_vol_set) {
1414 DEBUG_MSG("Setting Volume Left[%f], Right[%f]", qaf_mod->vol_left, qaf_mod->vol_right);
1415 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.set_volume(
1416 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1417 qaf_mod->vol_left,
1418 qaf_mod->vol_right);
1419 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001420
1421 int index = -1;
1422 if (qaf_mod->adsp_hdlr_config[QAF_IN_MAIN].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301423 index = (int) QAF_IN_MAIN;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001424 else if (qaf_mod->adsp_hdlr_config[QAF_IN_PCM].adsp_hdlr_config_valid)
Harsh Bansal28718c52017-04-20 13:47:12 +05301425 index = (int) QAF_IN_PCM;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001426 if (index >= 0) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301427 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]->standby) {
1428 qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
1429 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], NULL, 0);
1430 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001431
Harsh Bansal28718c52017-04-20 13:47:12 +05301432 lock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001433 ret = audio_extn_out_set_param_data(
Harsh Bansal28718c52017-04-20 13:47:12 +05301434 qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1435 AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
1436 (audio_extn_param_payload *)&qaf_mod->adsp_hdlr_config[index].event_params);
1437 unlock_output_stream(qaf_mod->stream_out[QAF_OUT_OFFLOAD]);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301438 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301439 }
1440
1441 /*
1442 * TODO:: Since this is mixed data,
1443 * need to identify to which stream the error should be sent
1444 */
Harsh Bansal28718c52017-04-20 13:47:12 +05301445 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
1446 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
1447 (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
1448 buf,
1449 size);
Varun B34da7a42017-02-13 16:16:53 +05301450 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301451 }
1452
Harsh Bansal28718c52017-04-20 13:47:12 +05301453 DEBUG_MSG("Bytes written = %d", ret);
1454 }
1455 else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
Varun B34da7a42017-02-13 16:16:53 +05301456 || event_id == AUDIO_EOS_MAIN_AAC_EVENT
1457 || event_id == AUDIO_EOS_MAIN_AC4_EVENT
1458 || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301459 struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
1460 struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
1461 bool *main_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
1462 bool *assoc_drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
Varun B34da7a42017-02-13 16:16:53 +05301463
1464 /**
1465 * TODO:: Only DD/DDP Associate Eos is handled, need to add support
1466 * for other formats.
1467 */
Harsh Bansal28718c52017-04-20 13:47:12 +05301468 if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
1469 && (out_assoc != NULL)
1470 && (*assoc_drain_received)) {
1471
Varun B34da7a42017-02-13 16:16:53 +05301472 lock_output_stream(out_assoc);
Harsh Bansal28718c52017-04-20 13:47:12 +05301473 out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_assoc->client_cookie);
1474 *assoc_drain_received = false;
1475 unlock_output_stream(out_assoc);
1476 DEBUG_MSG("sent associated DRAIN_READY");
1477 } else if ((out != NULL) && (*main_drain_received)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301478 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001479 out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
Harsh Bansal28718c52017-04-20 13:47:12 +05301480 *main_drain_received = false;
1481 unlock_output_stream(out);
1482 DEBUG_MSG("sent main DRAIN_READY");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301483 }
1484 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301485#if 0
1486 else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) { //TODO: For DTS
1487 struct stream_out *out = NULL;
1488 bool *drain_received = NULL;
1489
1490 if (event_id == AUDIO_MAIN_EOS_EVENT) {
1491 out = qaf_mod->stream_in[QAF_IN_MAIN];
1492 drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
1493 } else {
1494 out = qaf_mod->stream_in[QAF_IN_ASSOC];
1495 drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
1496 }
1497
1498 if ((out != NULL) && (*drain_received)) {
1499 lock_output_stream(out);
1500 out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
1501 *drain_received = false;
1502 unlock_output_stream(out);
1503 DEBUG_MSG("sent DRAIN_READY");
1504 }
1505 }
1506#endif
1507
1508 pthread_mutex_unlock(&p_qaf->lock);
1509 return;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301510}
1511
Harsh Bansal28718c52017-04-20 13:47:12 +05301512/* Close the mm module session. */
1513static int qaf_session_close(struct qaf_module* qaf_mod)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301514{
Harsh Bansal28718c52017-04-20 13:47:12 +05301515 int j;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301516
Harsh Bansal28718c52017-04-20 13:47:12 +05301517 //Check if all streams are closed or not.
1518 for (j = 0; j < MAX_QAF_MODULE_IN; j++) {
1519 if (qaf_mod->stream_in[j] != NULL) {
1520 break;
1521 }
1522 }
1523 if (j != MAX_QAF_MODULE_IN) {
1524 return 0; //Some stream is already active, Can not close session.
1525 }
1526
1527 if (qaf_mod->session_handle != NULL && qaf_mod->qaf_audio_session_close) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301528 qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
1529 qaf_mod->session_handle = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301530 qaf_mod->is_vol_set = false;
1531 memset(qaf_mod->drain_received, 0, sizeof(qaf_mod->drain_received));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301532 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301533
1534 for (j = 0; j < MAX_QAF_MODULE_OUT; j++) {
1535 if (qaf_mod->stream_out[j]) {
1536 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
1537 (struct audio_stream_out *)(qaf_mod->stream_out[j]));
1538 qaf_mod->stream_out[j] = NULL;
1539 }
1540 }
1541
1542 DEBUG_MSG("Session Closed.");
1543
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301544 return 0;
1545}
1546
Harsh Bansal28718c52017-04-20 13:47:12 +05301547/* Close the stream of QAF module. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301548static int qaf_stream_close(struct stream_out *out)
1549{
Harsh Bansal28718c52017-04-20 13:47:12 +05301550 int ret = -EINVAL;
1551 struct qaf_module *qaf_mod = NULL;
1552 int index = -1;
1553 DEBUG_MSG("Flag [0x%x], Stream handle [%p]", out->flags, out->qaf_stream_handle);
1554
1555 qaf_mod = get_qaf_module_for_input_stream(out);
1556 index = get_input_stream_index(out);
1557
1558 if (!qaf_mod || !qaf_mod->qaf_audio_stream_close || index < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301559 return -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301560 }
1561
1562 qaf_mod->stream_in[index] = NULL;
1563 memset(&qaf_mod->adsp_hdlr_config[index], 0, sizeof(struct qaf_adsp_hdlr_config_state));
1564
1565 lock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301566 if (out->qaf_stream_handle) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301567 ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
1568 out->qaf_stream_handle = NULL;
1569 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301570 unlock_output_stream(out);
1571
1572 //If all streams are closed then close the session.
1573 qaf_session_close(qaf_mod);
1574
1575 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301576 return ret;
1577}
1578
Harsh Bansal28718c52017-04-20 13:47:12 +05301579/* Open a MM module session with QAF. */
1580static int audio_extn_qaf_session_open(mm_module_type mod_type)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301581{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301582 ALOGV("%s %d", __func__, __LINE__);
Harsh Bansal28718c52017-04-20 13:47:12 +05301583 unsigned char* license_data = NULL;
1584 device_license_config_t lic_config = {0};
1585 int ret = -ENOSYS, size = 0;
1586 char value[PROPERTY_VALUE_MAX] = {0};
1587 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301588
Harsh Bansal28718c52017-04-20 13:47:12 +05301589 if (mod_type >= MAX_MM_MODULE_TYPE || !(p_qaf->qaf_mod[mod_type].qaf_audio_session_open))
1590 return -ENOTSUP; //Not supported by QAF module.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301591
Harsh Bansal28718c52017-04-20 13:47:12 +05301592 pthread_mutex_lock(&p_qaf->lock);
1593
1594 qaf_mod = &(p_qaf->qaf_mod[mod_type]);
1595
1596 //If session is already opened then return.
1597 if (qaf_mod->session_handle) {
1598 DEBUG_MSG("Session is already opened.");
1599 pthread_mutex_unlock(&p_qaf->lock);
1600 return 0;
1601 }
1602
1603 if (mod_type == MS12) {
1604 //Getting the license
1605 license_data = platform_get_license((struct audio_hw_device *)(p_qaf->adev->platform),
1606 &size);
1607 if (!license_data) {
1608 ERROR_MSG("License data is not present.");
1609 pthread_mutex_unlock(&p_qaf->lock);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301610 return -EINVAL;
1611 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301612
1613 lic_config.p_license = (unsigned char*)calloc(1, size);
1614 if (lic_config.p_license == NULL) {
1615 ERROR_MSG("Out of Memory");
1616 ret = -ENOMEM;
1617 goto exit;
1618 }
1619
1620 lic_config.l_size = size;
1621 memcpy(lic_config.p_license, license_data, size);
1622
1623 if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
1624 lic_config.manufacturer_id = (unsigned long)atoi(value);
1625 } else {
1626 ERROR_MSG("audio.qaf.manufacturer id is not set");
1627 ret = -EINVAL;
1628 goto exit;
1629 }
1630 }
1631
1632 ret = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
1633 (void *)(qaf_mod),
1634 (void *)&lic_config);
1635 if (ret < 0) {
1636 ERROR_MSG("Error in session open %d", ret);
1637 goto exit;
1638 }
1639
1640 if (qaf_mod->session_handle == NULL) {
1641 ERROR_MSG("Session handle is NULL.");
1642 ret = -ENOMEM;
1643 goto exit;
1644 }
1645
1646 if (qaf_mod->qaf_register_event_callback)
1647 qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
1648 qaf_mod,
1649 &notify_event_callback,
1650 AUDIO_DATA_EVENT);
1651
1652 set_hdmi_configuration_to_module();
1653
1654exit:
1655 if (license_data != NULL) {
1656 free(license_data);
1657 license_data = NULL;
1658 }
1659 if (lic_config.p_license != NULL) {
1660 free(lic_config.p_license);
1661 lic_config.p_license = NULL;
1662 }
1663
1664 pthread_mutex_unlock(&p_qaf->lock);
1665 return ret;
1666}
1667
1668/* opens a stream in QAF module. */
1669static int qaf_stream_open(struct stream_out *out,
1670 struct audio_config *config,
1671 audio_output_flags_t flags,
1672 audio_devices_t devices)
1673{
1674 int status = -EINVAL;
1675 mm_module_type mmtype = get_mm_module_for_format(config->format);
1676 struct qaf_module* qaf_mod = NULL;
1677 DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
1678
1679 if (mmtype >= MAX_MM_MODULE_TYPE
1680 || p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL
1681 || p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
1682 ERROR_MSG("Unsupported Stream");
1683 return -ENOTSUP;
1684 }
1685
1686 //Open the module session, if not opened already.
1687 status = audio_extn_qaf_session_open(mmtype);
1688 qaf_mod = &(p_qaf->qaf_mod[mmtype]);
1689
1690 if ((status != 0) || (qaf_mod->session_handle == NULL)) {
1691 ERROR_MSG("Failed to open session.");
1692 return status;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301693 }
1694
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301695 audio_stream_config_t input_config;
1696 input_config.sample_rate = config->sample_rate;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301697 input_config.channels = popcount(config->channel_mask);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301698 input_config.format = config->format;
1699
Harsh Bansal28718c52017-04-20 13:47:12 +05301700 if (input_config.format != AUDIO_FORMAT_PCM_16_BIT) {
1701 input_config.format &= AUDIO_FORMAT_MAIN_MASK;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301702 }
1703
Harsh Bansal28718c52017-04-20 13:47:12 +05301704 DEBUG_MSG("stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)",
1705 input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301706
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301707 if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301708 //If PCM stream is already opened then fail this stream open.
1709 if (qaf_mod->stream_in[QAF_IN_PCM]) {
1710 ERROR_MSG("PCM input is already active.");
1711 return -ENOTSUP;
1712 }
1713
1714 //TODO: Flag can be system tone or external associated PCM.
1715 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
1716 &out->qaf_stream_handle,
1717 input_config,
1718 devices,
1719 AUDIO_STREAM_SYSTEM_TONE);
1720 qaf_mod->stream_in[QAF_IN_PCM] = out;
1721 } else {
1722 if (!qaf_mod->stream_in[QAF_IN_MAIN]) {
1723 if ((!(flags & AUDIO_OUTPUT_FLAG_MAIN)) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
1724 ERROR_MSG("Error main input is not active.");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301725 return -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301726 }
1727
1728 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
1729 &out->qaf_stream_handle,
1730 input_config,
1731 devices,
1732 AUDIO_STREAM_MAIN);
1733 if (status == 0) {
1734 DEBUG_MSG("Open stream for Input with Main stream contents with flag [%x] and stream handle [%p]",
1735 flags, out->qaf_stream_handle);
1736 qaf_mod->stream_in[QAF_IN_MAIN] = out;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301737 }
1738 } else {
1739 if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301740 ERROR_MSG("Error main input is already active");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301741 return -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301742 } else if ((flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)
1743 && (!qaf_mod->stream_in[QAF_IN_ASSOC])) {
1744 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle,
1745 &out->qaf_stream_handle,
1746 input_config,
1747 devices,
1748 AUDIO_STREAM_ASSOCIATED);
1749 if (status == 0) {
1750 DEBUG_MSG("Open stream for Input with only Associated flag [%x] stream handle [%p]",
1751 flags, out->qaf_stream_handle);
1752 qaf_mod->stream_in[QAF_IN_ASSOC] = out;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301753 }
1754 } else {
Harsh Bansal28718c52017-04-20 13:47:12 +05301755 ERROR_MSG("Invalid flag or associated is already active");
1756 status = -EINVAL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301757 }
1758 }
1759 }
1760
Harsh Bansal28718c52017-04-20 13:47:12 +05301761 if (status != 0) {
1762 //If no stream is active then close the session.
1763 qaf_session_close(qaf_mod);
1764 return status;
1765 }
1766
1767 //If Device is HDMI, QAF passthrough is enabled and there is no previous QAF passthrough input stream.
1768 if ((!p_qaf->passthrough_in)
1769 && (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1770 && audio_extn_qaf_passthrough_enabled(out)) {
1771 //Assign the QAF passthrough input stream.
1772 p_qaf->passthrough_in = out;
1773
1774 //If HDMI is connected and format is supported by HDMI then create QAF passthrough output stream.
1775 if (p_qaf->hdmi_connect
1776 && platform_is_edid_supported_format(p_qaf->adev->platform, out->format)) {
1777 status = create_qaf_passthrough_stream();
1778 if (status < 0) {
1779 qaf_stream_close(out);
1780 ERROR_MSG("QAF passthrough stream creation failed with error %d", status);
1781 return status;
1782 }
1783 }
1784 /*Else: since QAF passthrough input stream is already initialized,
1785 * when hdmi is connected
1786 * then qaf passthrough output stream will be created.
1787 */
1788 }
1789
1790 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301791 return status;
1792}
1793
Harsh Bansal28718c52017-04-20 13:47:12 +05301794/* Resume a QAF stream. */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301795static int qaf_out_resume(struct audio_stream_out* stream)
1796{
1797 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05301798 int status = 0;
1799 DEBUG_MSG("Output Stream %p", out);
1800
1801
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301802 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301803
1804 //If QAF passthrough is active then block the resume on module input streams.
1805 if (p_qaf->passthrough_out) {
1806 //If resume is received for the QAF passthrough stream then call the primary HAL api.
1807 pthread_mutex_lock(&p_qaf->lock);
1808 if (p_qaf->passthrough_in == out) {
1809 status = p_qaf->passthrough_out->stream.resume(
1810 (struct audio_stream_out*)p_qaf->passthrough_out);
1811 if (!status) out->offload_state = OFFLOAD_STATE_PLAYING;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301812 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301813 pthread_mutex_unlock(&p_qaf->lock);
1814 } else {
1815 //Flush the module input stream.
1816 status = qaf_stream_start(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301817 }
1818
Harsh Bansal28718c52017-04-20 13:47:12 +05301819 unlock_output_stream(out);
1820
1821 DEBUG_MSG();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301822 return status;
1823}
1824
Harsh Bansal28718c52017-04-20 13:47:12 +05301825/* Offload thread for QAF output streams. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301826static void *qaf_offload_thread_loop(void *context)
1827{
Harsh Bansal28718c52017-04-20 13:47:12 +05301828 struct stream_out *out = (struct stream_out *)context;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301829 struct listnode *item;
1830 int ret = 0;
1831 struct str_parms *parms = NULL;
1832 int value = 0;
1833 char* kvpairs = NULL;
Harsh Bansal28718c52017-04-20 13:47:12 +05301834 struct qaf_module *qaf_mod = NULL;
1835
1836 qaf_mod = get_qaf_module_for_input_stream(out);
1837
1838 if (!qaf_mod) return NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301839
1840 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1841 set_sched_policy(0, SP_FOREGROUND);
1842 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
1843
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301844 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301845
1846 DEBUG_MSG();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301847 for (;;) {
1848 struct offload_cmd *cmd = NULL;
1849 stream_callback_event_t event;
1850 bool send_callback = false;
1851
Harsh Bansal28718c52017-04-20 13:47:12 +05301852 DEBUG_MSG("List Empty %d (1:TRUE, 0:FALSE)", list_empty(&out->qaf_offload_cmd_list));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301853 if (list_empty(&out->qaf_offload_cmd_list)) {
Harsh Bansal28718c52017-04-20 13:47:12 +05301854 DEBUG_MSG("SLEEPING");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301855 pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
Harsh Bansal28718c52017-04-20 13:47:12 +05301856 DEBUG_MSG("RUNNING");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301857 continue;
1858 }
1859
1860 item = list_head(&out->qaf_offload_cmd_list);
1861 cmd = node_to_item(item, struct offload_cmd, node);
1862 list_remove(item);
1863
1864 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
1865 free(cmd);
1866 break;
1867 }
1868
Harsh Bansal28718c52017-04-20 13:47:12 +05301869 unlock_output_stream(out);
1870
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301871 send_callback = false;
Harsh Bansal28718c52017-04-20 13:47:12 +05301872 switch (cmd->cmd) {
1873 case OFFLOAD_CMD_WAIT_FOR_BUFFER: {
1874 DEBUG_MSG("wait for buffer availability");
1875
1876 while (1) {
1877 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle,
1878 "buf_available");
1879 if (kvpairs) {
1880 parms = str_parms_create_str(kvpairs);
1881 ret = str_parms_get_int(parms, "buf_available", &value);
1882 if (ret >= 0) {
1883 if (value >= (int)out->compr_config.fragment_size) {
1884 DEBUG_MSG("buffer available");
1885 str_parms_destroy(parms);
1886 parms = NULL;
1887 break;
1888 } else {
1889 DEBUG_MSG("sleep");
1890 str_parms_destroy(parms);
1891 parms = NULL;
1892 usleep(10000);
1893 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301894 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301895 free(kvpairs);
1896 kvpairs = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301897 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301898 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301899 send_callback = true;
1900 event = STREAM_CBK_EVENT_WRITE_READY;
1901 break;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301902 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301903 default:
1904 DEBUG_MSG("unknown command received: %d", cmd->cmd);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301905 break;
1906 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301907
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301908 lock_output_stream(out);
Harsh Bansal28718c52017-04-20 13:47:12 +05301909
Ben Rombergerd771a7c2017-02-22 18:05:17 -08001910 if (send_callback && out->client_callback) {
1911 out->client_callback(event, NULL, out->client_cookie);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301912 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301913
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301914 free(cmd);
1915 }
1916
1917 while (!list_empty(&out->qaf_offload_cmd_list)) {
1918 item = list_head(&out->qaf_offload_cmd_list);
1919 list_remove(item);
Harsh Bansal28718c52017-04-20 13:47:12 +05301920 free (node_to_item( item, struct offload_cmd, node));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301921 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301922 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301923
1924 return NULL;
1925}
1926
Harsh Bansal28718c52017-04-20 13:47:12 +05301927/* Create the offload callback thread for QAF output stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301928static int qaf_create_offload_callback_thread(struct stream_out *out)
1929{
Harsh Bansal28718c52017-04-20 13:47:12 +05301930 DEBUG_MSG("Output Stream %p", out);
1931 lock_output_stream(out);
1932 pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *)NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301933 list_init(&out->qaf_offload_cmd_list);
Harsh Bansal28718c52017-04-20 13:47:12 +05301934 pthread_create(&out->qaf_offload_thread,
1935 (const pthread_attr_t *)NULL,
1936 qaf_offload_thread_loop,
1937 out);
1938 unlock_output_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301939 return 0;
1940}
1941
Harsh Bansal28718c52017-04-20 13:47:12 +05301942/* Destroy the offload callback thread of QAF output stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301943static int qaf_destroy_offload_callback_thread(struct stream_out *out)
1944{
Harsh Bansal28718c52017-04-20 13:47:12 +05301945 DEBUG_MSG("Output Stream %p", out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301946 qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301947
Harsh Bansal28718c52017-04-20 13:47:12 +05301948 pthread_join(out->qaf_offload_thread, (void **)NULL);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301949 pthread_cond_destroy(&out->qaf_offload_cond);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301950 return 0;
1951}
1952
Harsh Bansal28718c52017-04-20 13:47:12 +05301953/* Sets the stream set parameters (device routing information). */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301954static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
1955{
1956 struct str_parms *parms, *new_parms;
1957 char value[32];
1958 char *new_kv_pairs;
1959 int val = 0;
1960 struct stream_out *out = (struct stream_out *)stream;
1961 int ret = 0;
1962 int err = 0;
Harsh Bansal28718c52017-04-20 13:47:12 +05301963 struct qaf_module *qaf_mod = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301964
Harsh Bansal28718c52017-04-20 13:47:12 +05301965 DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301966
Harsh Bansal28718c52017-04-20 13:47:12 +05301967 parms = str_parms_create_str(kvpairs);
1968 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
1969 if (err < 0)
1970 return err;
1971 val = atoi(value);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301972
Harsh Bansal28718c52017-04-20 13:47:12 +05301973 qaf_mod = get_qaf_module_for_input_stream(out);
1974 if (!qaf_mod) return (-EINVAL);
1975
1976 //TODO: HDMI is connected but user doesn't want HDMI output, close both HDMI outputs.
1977
1978 /* Setting new device information to the mm module input streams.
1979 * This is needed if QAF module output streams are not created yet.
1980 */
1981 if (qaf_mod->stream_in[QAF_IN_MAIN] == out || qaf_mod->stream_in[QAF_IN_ASSOC] == out) {
1982 qaf_mod->stream_in[QAF_IN_MAIN]->devices = val;
1983 } else {
1984 out->devices = val;
1985 }
1986
1987 if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
1988 //If device is BT then open the BT stream if not already opened.
1989 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) == NULL
1990 && audio_extn_bt_hal_get_device(qaf_mod->bt_hdl) != NULL) {
1991 ret = audio_extn_bt_hal_open_output_stream(qaf_mod->bt_hdl,
1992 QAF_OUTPUT_SAMPLING_RATE,
1993 AUDIO_CHANNEL_OUT_STEREO,
1994 CODEC_BACKEND_DEFAULT_BIT_WIDTH);
1995 if (ret != 0) {
1996 ERROR_MSG("BT Output stream open failure!");
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301997 }
Harsh Bansal28718c52017-04-20 13:47:12 +05301998 }
1999 } else if (val != 0) {
2000 //If device is not BT then close the BT stream if already opened.
2001 if ( audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl) != NULL) {
2002 audio_extn_bt_hal_close_output_stream(qaf_mod->bt_hdl);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302003 }
2004 }
2005
Harsh Bansal28718c52017-04-20 13:47:12 +05302006 if (p_qaf->passthrough_in == out) { //Device routing is received for QAF passthrough stream.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302007
Harsh Bansal28718c52017-04-20 13:47:12 +05302008 if (!(val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) { //HDMI route is disabled.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302009
Harsh Bansal28718c52017-04-20 13:47:12 +05302010 //If QAF pasthrough output is enabled. Close it.
2011 close_qaf_passthrough_stream();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302012
Harsh Bansal28718c52017-04-20 13:47:12 +05302013 //Send the routing information to mm module pcm output.
2014 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
2015 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
2016 (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302017 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302018 //else: device info is updated in the input streams.
2019 } else { //HDMI route is enabled.
2020
2021 //create the QAf passthrough stream, if not created already.
2022 ret = create_qaf_passthrough_stream();
2023
2024 if (p_qaf->passthrough_out != NULL) { //If QAF passthrough out is enabled then send routing information.
2025 ret = p_qaf->passthrough_out->stream.common.set_parameters(
2026 (struct audio_stream *)p_qaf->passthrough_out, kvpairs);
2027 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302028 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302029 } else {
2030 //Send the routing information to mm module pcm output.
2031 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
2032 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.common.set_parameters(
2033 (struct audio_stream *)qaf_mod->stream_out[QAF_OUT_OFFLOAD], kvpairs);
2034 }
2035 //else: device info is updated in the input streams.
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302036 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302037 str_parms_destroy(parms);
2038
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002039 return ret;
2040}
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302041
Harsh Bansal28718c52017-04-20 13:47:12 +05302042/* Checks if a stream is QAF stream or not. */
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002043bool audio_extn_is_qaf_stream(struct stream_out *out)
2044{
Harsh Bansal28718c52017-04-20 13:47:12 +05302045 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002046
Harsh Bansal28718c52017-04-20 13:47:12 +05302047 if (qaf_mod) {
2048 return true;
2049 }
2050 return false;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002051}
2052
2053/* API to send playback stream specific config parameters */
2054int audio_extn_qaf_out_set_param_data(struct stream_out *out,
Harsh Bansal28718c52017-04-20 13:47:12 +05302055 audio_extn_param_id param_id,
2056 audio_extn_param_payload *payload)
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002057{
2058 int ret = -EINVAL;
Harsh Bansal28718c52017-04-20 13:47:12 +05302059 int index;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002060 struct stream_out *new_out = NULL;
2061 struct audio_adsp_event *adsp_event;
Harsh Bansal28718c52017-04-20 13:47:12 +05302062 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002063
Harsh Bansal28718c52017-04-20 13:47:12 +05302064 if (!out || !qaf_mod || !payload) {
2065 ERROR_MSG("Invalid Param");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002066 return ret;
2067 }
2068
2069 /* In qaf output render session may not be opened at this time.
Harsh Bansal28718c52017-04-20 13:47:12 +05302070 to handle it store adsp_hdlr param info so that it can be
2071 applied later after opening render session from ms12 callback
2072 */
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002073 if (param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302074 index = get_input_stream_index(out);
2075 if (index < 0) {
2076 ERROR_MSG("Invalid stream");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002077 return ret;
2078 }
2079 adsp_event = (struct audio_adsp_event *)payload;
2080
Harsh Bansal28718c52017-04-20 13:47:12 +05302081 if (payload->adsp_event_params.payload_length <= AUDIO_MAX_ADSP_STREAM_CMD_PAYLOAD_LEN) {
2082 pthread_mutex_lock(&p_qaf->lock);
2083 memcpy(qaf_mod->adsp_hdlr_config[index].event_payload,
2084 adsp_event->payload,
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002085 adsp_event->payload_length);
Harsh Bansal28718c52017-04-20 13:47:12 +05302086 qaf_mod->adsp_hdlr_config[index].event_params.payload =
2087 qaf_mod->adsp_hdlr_config[index].event_payload;
2088 qaf_mod->adsp_hdlr_config[index].event_params.payload_length =
2089 adsp_event->payload_length;
2090 qaf_mod->adsp_hdlr_config[index].adsp_hdlr_config_valid = true;
2091 pthread_mutex_unlock(&p_qaf->lock);
2092 } else {
2093 ERROR_MSG("Invalid adsp event length %d", adsp_event->payload_length);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002094 return ret;
2095 }
2096 ret = 0;
2097 }
2098
Harsh Bansal28718c52017-04-20 13:47:12 +05302099 /* apply param for all active out sessions */
2100 for (index = 0; index < MAX_QAF_MODULE_OUT; index++) {
2101 new_out = qaf_mod->stream_out[index];
2102 if (!new_out) continue;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002103
Harsh Bansal28718c52017-04-20 13:47:12 +05302104 /*ADSP event is not supported for passthrough*/
2105 if ((param_id == AUDIO_EXTN_PARAM_ADSP_STREAM_CMD)
2106 && !(new_out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM)) continue;
2107 if (new_out->standby)
2108 new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
2109 lock_output_stream(new_out);
2110 ret = audio_extn_out_set_param_data(new_out, param_id, payload);
2111 if (ret)
2112 ERROR_MSG("audio_extn_out_set_param_data error %d", ret);
2113 unlock_output_stream(new_out);
2114 }
2115 return ret;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002116}
2117
2118int audio_extn_qaf_out_get_param_data(struct stream_out *out,
2119 audio_extn_param_id param_id,
2120 audio_extn_param_payload *payload)
2121{
Harsh Bansal28718c52017-04-20 13:47:12 +05302122 int ret = -EINVAL, i;
2123 struct stream_out *new_out;
2124 struct audio_usecase *uc_info;
2125 struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002126
Harsh Bansal28718c52017-04-20 13:47:12 +05302127 if (!out || !qaf_mod || !payload) {
2128 ERROR_MSG("Invalid Param");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002129 return ret;
2130 }
2131
Harsh Bansal28718c52017-04-20 13:47:12 +05302132 if (!p_qaf->hdmi_connect) {
2133 ERROR_MSG("hdmi not connected");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002134 return ret;
2135 }
2136
2137 /* get session which is routed to hdmi*/
Harsh Bansal28718c52017-04-20 13:47:12 +05302138 if (p_qaf->passthrough_out)
2139 new_out = p_qaf->passthrough_out;
2140 else {
2141 for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
2142 if (qaf_mod->stream_out[i]) {
2143 new_out = qaf_mod->stream_out[i];
2144 break;
2145 }
2146 }
2147 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002148
2149 if (!new_out) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302150 ERROR_MSG("No stream active.");
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002151 return ret;
2152 }
2153
2154 if (new_out->standby)
Harsh Bansal28718c52017-04-20 13:47:12 +05302155 new_out->stream.write((struct audio_stream_out *)new_out, NULL, 0);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002156
2157 lock_output_stream(new_out);
2158 ret = audio_extn_out_get_param_data(new_out, param_id, payload);
Harsh Bansal28718c52017-04-20 13:47:12 +05302159 if (ret)
2160 ERROR_MSG("audio_extn_out_get_param_data error %d", ret);
2161 unlock_output_stream(new_out);
2162
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302163 return ret;
2164}
2165
Harsh Bansal28718c52017-04-20 13:47:12 +05302166/* To open a stream with QAF. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302167int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
Harsh Bansal28718c52017-04-20 13:47:12 +05302168 audio_io_handle_t handle,
2169 audio_devices_t devices,
2170 audio_output_flags_t flags,
2171 struct audio_config *config,
2172 struct audio_stream_out **stream_out,
2173 const char *address)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302174{
2175 int ret = 0;
2176 struct stream_out *out;
2177
2178 ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
2179 if (*stream_out == NULL) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302180 ERROR_MSG("Stream open failed %d", ret);
Deepak Agarwal1e42b852017-02-11 17:57:04 +05302181 return ret;
2182 }
2183
Harsh Bansal28718c52017-04-20 13:47:12 +05302184 out = (struct stream_out *)*stream_out;
2185
2186 ret = qaf_stream_open(out, config, flags, devices);
2187 if (ret == -ENOTSUP) {
2188 //Stream not supported by QAF, Bypass QAF.
2189 return 0;
2190 } else if (ret < 0) {
2191 ERROR_MSG("Error opening QAF stream err[%d]!", ret);
2192 adev_close_output_stream(dev, *stream_out);
2193 return ret;
2194 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302195
2196 /* Override function pointers based on qaf definitions */
2197 out->stream.set_volume = qaf_out_set_volume;
2198 out->stream.pause = qaf_out_pause;
2199 out->stream.resume = qaf_out_resume;
2200 out->stream.drain = qaf_out_drain;
2201 out->stream.flush = qaf_out_flush;
2202
2203 out->stream.common.standby = qaf_out_standby;
2204 out->stream.common.set_parameters = qaf_out_set_parameters;
2205 out->stream.get_latency = qaf_out_get_latency;
2206 out->stream.write = qaf_out_write;
2207 out->stream.get_presentation_position = qaf_out_get_presentation_position;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302208 out->platform_latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302209
Harsh Bansal28718c52017-04-20 13:47:12 +05302210 /*TODO: Need to handle this for DTS*/
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302211 if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
2212 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
Varun B34da7a42017-02-13 16:16:53 +05302213 out->config.period_size = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302214 out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
Varun B34da7a42017-02-13 16:16:53 +05302215 out->config.start_threshold = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
2216 out->config.avail_min = QAF_DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302217 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302218 *stream_out = &out->stream;
2219 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
2220 qaf_create_offload_callback_thread(out);
2221 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302222
2223 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302224 return 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302225}
2226
Harsh Bansal28718c52017-04-20 13:47:12 +05302227/* Close a QAF stream. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302228void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
Harsh Bansal28718c52017-04-20 13:47:12 +05302229 struct audio_stream_out *stream)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302230{
2231 struct stream_out *out = (struct stream_out *)stream;
Harsh Bansal28718c52017-04-20 13:47:12 +05302232 struct qaf_module* qaf_mod = get_qaf_module_for_input_stream(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302233
Harsh Bansal28718c52017-04-20 13:47:12 +05302234 if (!qaf_mod) return;
2235
2236 DEBUG_MSG("stream_handle(%p) format = %x", out, out->format);
2237
2238 //If close is received for QAF passthrough stream then close the QAF passthrough output.
2239 if (p_qaf->passthrough_in == out) {
2240 if (p_qaf->passthrough_out) {
2241 ALOGD("%s %d closing stream handle %p", __func__, __LINE__, p_qaf->passthrough_out);
2242 pthread_mutex_lock(&p_qaf->lock);
2243 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
2244 (struct audio_stream_out *)(p_qaf->passthrough_out));
2245 pthread_mutex_unlock(&p_qaf->lock);
2246 p_qaf->passthrough_out = NULL;
2247 }
2248
2249 p_qaf->passthrough_in = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302250 }
2251
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302252 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
2253 qaf_destroy_offload_callback_thread(out);
2254 }
Ben Rombergerd771a7c2017-02-22 18:05:17 -08002255
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302256 qaf_stream_close(out);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302257
2258 adev_close_output_stream(dev, stream);
Harsh Bansal28718c52017-04-20 13:47:12 +05302259
2260 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302261}
2262
Harsh Bansal28718c52017-04-20 13:47:12 +05302263/* Check if QAF is supported or not. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302264bool audio_extn_qaf_is_enabled()
2265{
2266 bool prop_enabled = false;
2267 char value[PROPERTY_VALUE_MAX] = {0};
2268 property_get("audio.qaf.enabled", value, NULL);
2269 prop_enabled = atoi(value) || !strncmp("true", value, 4);
2270 return (prop_enabled);
2271}
2272
Harsh Bansal28718c52017-04-20 13:47:12 +05302273/* Query HDMI EDID and sets module output accordingly.*/
2274void set_hdmi_configuration_to_module()
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302275{
Harsh Bansal28718c52017-04-20 13:47:12 +05302276 int channels = 0;
2277 char *format_params;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302278 struct str_parms *qaf_params;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05302279 char prop_value[PROPERTY_VALUE_MAX];
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302280 bool passth_support = false;
2281
Harsh Bansal28718c52017-04-20 13:47:12 +05302282 DEBUG_MSG("Entry");
2283
2284 if (!p_qaf) {
2285 return;
2286 }
2287
2288 if (!p_qaf->hdmi_connect) {
2289 DEBUG_MSG("HDMI is not connected.");
2290 return;
2291 }
2292
2293 p_qaf->hdmi_sink_channels = 0;
2294
2295 //QAF re-encoding and DSP offload passthrough is supported.
2296 if (property_get_bool("audio.offload.passthrough", false)
2297 && property_get_bool("audio.qaf.reencode", false)) {
2298
2299 //If MS12 session is active.
2300 if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
2301
2302 bool do_setparam = false;
2303 qaf_params = str_parms_create();
2304 property_get("audio.qaf.hdmi.out", prop_value, NULL);
2305
2306 if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_E_AC3)
2307 && (strncmp(prop_value, "ddp", 3) == 0)) {
2308 do_setparam = true;
2309 if (qaf_params) {
2310 str_parms_add_str(qaf_params,
2311 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2312 AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
2313 }
2314 } else if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_AC3)) {
2315 do_setparam = true;
2316 if (qaf_params) {
2317 str_parms_add_str(qaf_params,
2318 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2319 AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
2320 }
2321 }
2322
2323 if (do_setparam) {
2324 if (p_qaf->qaf_msmd_enabled) {
2325 str_parms_add_str(qaf_params,
2326 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2327 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
2328 } else {
2329 str_parms_add_str(qaf_params,
2330 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2331 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2332 }
2333 format_params = str_parms_to_str(qaf_params);
2334
2335 p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
2336 format_params);
2337
2338 passth_support = true;
2339 }
2340 str_parms_destroy(qaf_params);
2341 }
2342
2343 //DTS_M8 session is active.
2344 if (p_qaf->qaf_mod[DTS_M8].session_handle
2345 && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
2346
2347 bool do_setparam = false;
2348 qaf_params = str_parms_create();
2349#if 0 //TODO: Need to enable with DTS_M8 wrapper.
2350 if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_DTS)) {
2351 do_setparam = true;
2352 if (qaf_params) {
2353 str_parms_add_str(qaf_params,
2354 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2355 AUDIO_QAF_PARAMETER_VALUE_REENCODE_DTS);
2356 }
2357 }
2358#endif
2359
2360 if (do_setparam) {
2361 if (p_qaf->qaf_msmd_enabled) {
2362 str_parms_add_str(qaf_params,
2363 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2364 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK); //TODO: Need enhancement.
2365 } else {
2366 str_parms_add_str(qaf_params,
2367 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2368 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2369 }
2370 format_params = str_parms_to_str(qaf_params);
2371
2372 p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
2373 format_params);
2374
2375 passth_support = true;
2376 }
2377 str_parms_destroy(qaf_params);
2378 }
2379 }
2380
2381 //Compressed passthrough is not enabled.
2382 if (!passth_support) {
2383
2384 channels = platform_edid_get_max_channels(p_qaf->adev->platform);
2385
2386 qaf_params = str_parms_create();
2387 switch (channels) {
2388 case 8:
2389 DEBUG_MSG("Switching Qaf output to 7.1 channels");
2390 str_parms_add_str(qaf_params,
2391 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2392 AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
2393 if (p_qaf->qaf_msmd_enabled) {
2394 str_parms_add_str(qaf_params,
2395 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2396 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2397 } else {
2398 str_parms_add_str(qaf_params,
2399 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2400 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2401 }
2402 p_qaf->hdmi_sink_channels = channels;
2403 break;
2404 case 6:
2405 DEBUG_MSG("Switching Qaf output to 5.1 channels");
2406 str_parms_add_str(qaf_params,
2407 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2408 AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
2409 if (p_qaf->qaf_msmd_enabled) {
2410 str_parms_add_str(qaf_params,
2411 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2412 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2413 } else {
2414 str_parms_add_str(qaf_params,
2415 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2416 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
2417 }
2418 p_qaf->hdmi_sink_channels = channels;
2419 break;
2420 default:
2421 DEBUG_MSG("Switching Qaf output to default channels");
2422 str_parms_add_str(qaf_params,
2423 AUDIO_QAF_PARAMETER_KEY_CHANNELS,
2424 AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
2425 if (p_qaf->qaf_msmd_enabled) {
2426 str_parms_add_str(qaf_params,
2427 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2428 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
2429 } else {
2430 str_parms_add_str(qaf_params,
2431 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2432 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
2433 }
2434 p_qaf->hdmi_sink_channels = 2;
2435 break;
2436 }
2437
2438 format_params = str_parms_to_str(qaf_params);
2439
2440 if (p_qaf->qaf_mod[MS12].session_handle && p_qaf->qaf_mod[MS12].qaf_audio_session_set_param) {
2441 p_qaf->qaf_mod[MS12].qaf_audio_session_set_param(p_qaf->qaf_mod[MS12].session_handle,
2442 format_params);
2443 }
2444 if (p_qaf->qaf_mod[DTS_M8].session_handle
2445 && p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param) {
2446 p_qaf->qaf_mod[DTS_M8].qaf_audio_session_set_param(p_qaf->qaf_mod[DTS_M8].session_handle,
2447 format_params);
2448 }
2449
2450 str_parms_destroy(qaf_params);
2451 }
2452 DEBUG_MSG("Exit");
2453}
2454
2455/* QAF set parameter function. For Device connect and disconnect. */
2456int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
2457{
2458 int status = 0, val = 0, k;
2459 char *format_params, *kv_parirs;
2460 struct str_parms *qaf_params;
2461 char value[32];
2462
2463 DEBUG_MSG("Entry");
2464
2465 if (!p_qaf) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302466 return -EINVAL;
2467 }
2468
2469 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
Harsh Bansal28718c52017-04-20 13:47:12 +05302470
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302471 if (status >= 0) {
2472 val = atoi(value);
Harsh Bansal28718c52017-04-20 13:47:12 +05302473 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is connected.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302474
Harsh Bansal28718c52017-04-20 13:47:12 +05302475 p_qaf->hdmi_connect = 1;
2476 p_qaf->hdmi_sink_channels = 0;
2477
2478 if (p_qaf->passthrough_in) { //If QAF passthrough is already initialized.
2479 lock_output_stream(p_qaf->passthrough_in);
2480 if (platform_is_edid_supported_format(adev->platform,
2481 p_qaf->passthrough_in->format)) {
2482 //If passthrough format is supported by HDMI then create the QAF passthrough output if not created already.
2483 create_qaf_passthrough_stream();
2484 //Ignoring the returned error, If error then QAF passthrough is disabled.
2485 } else {
2486 //If passthrough format is not supported by HDMI then close the QAF passthrough output if already created.
2487 close_qaf_passthrough_stream();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302488 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302489 unlock_output_stream(p_qaf->passthrough_in);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302490 }
2491
Harsh Bansal28718c52017-04-20 13:47:12 +05302492 set_hdmi_configuration_to_module();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302493
Bharath Gopal01310bb2016-12-05 15:39:32 +05302494 } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302495 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2496 if (!p_qaf->qaf_mod[k].bt_hdl) {
2497 DEBUG_MSG("Opening a2dp output...");
2498 status = audio_extn_bt_hal_load(&p_qaf->qaf_mod[k].bt_hdl);
2499 if (status != 0) {
2500 ERROR_MSG("Error opening BT module");
2501 return status;
2502 }
2503 }
Bharath Gopal01310bb2016-12-05 15:39:32 +05302504 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302505 }
Harsh Bansal28718c52017-04-20 13:47:12 +05302506 //TODO else if: Need to consider other devices.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302507 }
2508
2509 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
2510 if (status >= 0) {
2511 val = atoi(value);
Harsh Bansal28718c52017-04-20 13:47:12 +05302512 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) { //HDMI is disconnected.
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302513
Harsh Bansal28718c52017-04-20 13:47:12 +05302514 qaf_params = str_parms_create();
2515 str_parms_add_str(qaf_params,
2516 AUDIO_QAF_PARAMETER_KEY_DEVICE,
2517 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
2518 str_parms_add_str(qaf_params,
2519 AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
2520 AUDIO_QAF_PARAMETER_VALUE_PCM);
2521 p_qaf->hdmi_sink_channels = 0;
2522
2523 p_qaf->passthrough_enabled = 0;
2524 p_qaf->mch_pcm_hdmi_enabled = 0;
2525 p_qaf->hdmi_connect = 0;
2526
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302527 format_params = str_parms_to_str(qaf_params);
Harsh Bansal28718c52017-04-20 13:47:12 +05302528
2529 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2530 if (p_qaf->qaf_mod[k].session_handle
2531 && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
2532 p_qaf->qaf_mod[k].qaf_audio_session_set_param(
2533 p_qaf->qaf_mod[k].session_handle, format_params);
2534 }
2535 }
2536 close_all_hdmi_output();
2537
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302538 str_parms_destroy(qaf_params);
Harsh Bansal28718c52017-04-20 13:47:12 +05302539 close_qaf_passthrough_stream();
Bharath Gopal01310bb2016-12-05 15:39:32 +05302540 } else if (val & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
Harsh Bansal28718c52017-04-20 13:47:12 +05302541 DEBUG_MSG("Closing a2dp output...");
2542 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2543 if (p_qaf->qaf_mod[k].bt_hdl) {
2544 audio_extn_bt_hal_unload(p_qaf->qaf_mod[k].bt_hdl);
2545 p_qaf->qaf_mod[k].bt_hdl = NULL;
2546 }
2547 }
2548 }
2549 //TODO else if: Need to consider other devices.
2550 }
2551
2552 for (k = 0; k < MAX_MM_MODULE_TYPE; k++) {
2553 kv_parirs = str_parms_to_str(parms);
2554 if (p_qaf->qaf_mod[k].session_handle && p_qaf->qaf_mod[k].qaf_audio_session_set_param) {
2555 p_qaf->qaf_mod[k].qaf_audio_session_set_param(
2556 p_qaf->qaf_mod[k].session_handle, kv_parirs);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302557 }
2558 }
2559
Harsh Bansal28718c52017-04-20 13:47:12 +05302560 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302561 return status;
2562}
2563
Harsh Bansal28718c52017-04-20 13:47:12 +05302564/* Create the QAF. */
2565int audio_extn_qaf_init(struct audio_device *adev)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302566{
Harsh Bansal28718c52017-04-20 13:47:12 +05302567 DEBUG_MSG("Entry");
2568
2569 p_qaf = calloc(1, sizeof(struct qaf));
2570 if (p_qaf == NULL) {
2571 ERROR_MSG("Out of memory");
2572 return -ENOMEM;
2573 }
2574
2575 p_qaf->adev = adev;
2576
2577 if (property_get_bool("audio.qaf.msmd", false)) {
2578 p_qaf->qaf_msmd_enabled = 1;
2579 }
2580 pthread_mutex_init(&p_qaf->lock, (const pthread_mutexattr_t *) NULL);
2581
2582 int i = 0;
2583
2584 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
2585 char value[PROPERTY_VALUE_MAX] = {0};
2586 char lib_name[PROPERTY_VALUE_MAX] = {0};
2587 struct qaf_module *qaf_mod = &(p_qaf->qaf_mod[i]);
2588
2589 if (i == MS12) {
2590 property_get("audio.qaf.library", value, NULL);
2591 } else if (i == DTS_M8) {
2592 property_get("audio.qaf.m8.library", value, NULL);
2593 } else {
2594 continue;
2595 }
2596
2597 snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
2598
2599 qaf_mod->qaf_lib = dlopen(lib_name, RTLD_NOW);
2600 if (qaf_mod->qaf_lib == NULL) {
2601 ERROR_MSG("DLOPEN failed for %s", lib_name);
2602 continue;
2603 }
2604
2605 DEBUG_MSG("DLOPEN successful for %s", lib_name);
2606 qaf_mod->qaf_audio_session_open =
2607 (int (*)(audio_session_handle_t* session_handle, void *p_data, void* license_data))dlsym(qaf_mod->qaf_lib,
2608 "audio_session_open");
2609 qaf_mod->qaf_audio_session_close =
2610 (int (*)(audio_session_handle_t session_handle))dlsym(qaf_mod->qaf_lib,
2611 "audio_session_close");
2612 qaf_mod->qaf_audio_stream_open =
2613 (int (*)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
2614 audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags))dlsym(qaf_mod->qaf_lib,
2615 "audio_stream_open");
2616 qaf_mod->qaf_audio_stream_close =
2617 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2618 "audio_stream_close");
2619 qaf_mod->qaf_audio_stream_set_param =
2620 (int (*)(audio_stream_handle_t stream_handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
2621 "audio_stream_set_param");
2622 qaf_mod->qaf_audio_session_set_param =
2623 (int (*)(audio_session_handle_t handle, const char* kv_pairs))dlsym(qaf_mod->qaf_lib,
2624 "audio_session_set_param");
2625 qaf_mod->qaf_audio_stream_get_param =
2626 (char* (*)(audio_stream_handle_t stream_handle, const char* key))dlsym(qaf_mod->qaf_lib,
2627 "audio_stream_get_param");
2628 qaf_mod->qaf_audio_session_get_param =
2629 (char* (*)(audio_session_handle_t handle, const char* key))dlsym(qaf_mod->qaf_lib,
2630 "audio_session_get_param");
2631 qaf_mod->qaf_audio_stream_start =
2632 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2633 "audio_stream_start");
2634 qaf_mod->qaf_audio_stream_stop =
2635 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2636 "audio_stream_stop");
2637 qaf_mod->qaf_audio_stream_pause =
2638 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2639 "audio_stream_pause");
2640 qaf_mod->qaf_audio_stream_flush =
2641 (int (*)(audio_stream_handle_t stream_handle))dlsym(qaf_mod->qaf_lib,
2642 "audio_stream_flush");
2643 qaf_mod->qaf_audio_stream_write =
2644 (int (*)(audio_stream_handle_t stream_handle, const void* buf, int size))dlsym(qaf_mod->qaf_lib,
2645 "audio_stream_write");
2646 qaf_mod->qaf_register_event_callback =
2647 (void (*)(audio_session_handle_t session_handle, void *priv_data, notify_event_callback_t event_callback,
2648 audio_event_id_t event_id))dlsym(qaf_mod->qaf_lib,
2649 "register_event_callback");
2650 }
2651
2652 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302653 return 0;
2654}
2655
Harsh Bansal28718c52017-04-20 13:47:12 +05302656/* Tear down the qaf extension. */
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302657void audio_extn_qaf_deinit()
2658{
Harsh Bansal28718c52017-04-20 13:47:12 +05302659 int i;
2660 DEBUG_MSG("Entry");
2661
2662 if (p_qaf != NULL) {
2663 for (i = 0; i < MAX_MM_MODULE_TYPE; i++) {
2664 qaf_session_close(&p_qaf->qaf_mod[i]);
2665
2666 if (p_qaf->qaf_mod[i].qaf_lib != NULL) {
2667 dlclose(p_qaf->qaf_mod[i].qaf_lib);
2668 p_qaf->qaf_mod[i].qaf_lib = NULL;
2669 }
2670 }
2671 if (p_qaf->passthrough_out) {
2672 adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
2673 (struct audio_stream_out *)(p_qaf->passthrough_out));
2674 p_qaf->passthrough_out = NULL;
2675 }
2676
2677 pthread_mutex_destroy(&p_qaf->lock);
2678 free(p_qaf);
2679 p_qaf = NULL;
2680 }
2681 DEBUG_MSG("Exit");
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05302682}