blob: d24d4d1af85c31cdc54e2c95166c4522e23312bc [file] [log] [blame]
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301/*
2 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
3 *
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
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053039#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 2
40#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053041#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
42#define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
43#define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +053044#define QAF_DEFAULT_PASSTHROUGH_HANDLE 1003
45/*
46 * MS12 Latency (Input Buffer Processing latency)+
47 * Kernel Latency (Calculated based on the available offload buffer size) +
48 * DSP Latency (Calculated based on the Platform render latency)
49*/
50#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 300
51#define PCM_OFFLOAD_PLAYBACK_LATENCY 248
52
53/*
54 * Buffer size for compress passthrough is 8192 bytes
55 */
56#define COMPRESS_PASSTHROUGH_BUFFER_SIZE \
57 (COMPRESS_OFFLOAD_NUM_FRAGMENTS * COMPRESS_OFFLOAD_FRAGMENT_SIZE)
58/*
59 * Frame size for DD/DDP is 1536 samples corresponding to 32ms.
60 */
61#define DD_FRAME_SIZE 1536
62/*
63 * DD encoder output size for 32ms.
64 */
65#define DD_ENCODER_OUTPUT_SIZE 2560
66/*
67 * DDP encoder output size for 32ms.
68 */
69#define DDP_ENCODER_OUTPUT_SIZE 4608
70
71/*
72 * Frame size for DD/DDP is 1536 samples.
73 * For a bit rate of 640 bps, DD encoder output size is 2560 bytes of
74 * 32ms;
75 * DDP encoder output size is 4608 bytes of 32 ms.
76 * Kernel buffer buffer allocation for compress passthrough is
77 * 2 x 2048 bytes = 4096 bytes
78 * The Latency for DD (measured in samples) is calculated as:
79 * Time taken to play 8192 bytes (for DD) = 4096 x 32/2560 = 51.2ms
80 * Samples for 51.2ms = 51.2 x 1536/32 = 2457 samples.
81 * Latency calculated similarly for DPP is 1365 samples.
82 */
83#define TRANSCODE_LATENCY(buffer_size, frame_size, encoder_output_in_bytes) ((buffer_size * frame_size) / encoder_output_in_bytes)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053084
85#include <stdlib.h>
86#include <pthread.h>
87#include <errno.h>
88#include <dlfcn.h>
89#include <sys/resource.h>
90#include <sys/prctl.h>
91#include <cutils/properties.h>
92#include <cutils/str_parms.h>
93#include <cutils/log.h>
94#include <cutils/atomic.h>
95#include "audio_utils/primitives.h"
96#include "audio_hw.h"
97#include "platform_api.h"
98#include <platform.h>
99#include <system/thread_defs.h>
100#include <cutils/sched_policy.h>
101#include "audio_extn.h"
102#include <qti_audio.h>
103#include "sound/compress_params.h"
104
105#define QAF_OUTPUT_SAMPLING_RATE 48000
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530106#define PCM_OFFLOAD_BUFFER_SIZE 7680
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530107
108#ifdef QAF_DUMP_ENABLED
109FILE *fp_output_writer_hdmi = NULL;
110#endif
111
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530112struct qaf {
113 struct audio_device *adev;
114 audio_session_handle_t session_handle;
115 void *qaf_lib;
116 int (*qaf_audio_session_open)(audio_session_handle_t* session_handle, void *p_data, void* license_data);
117 int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
118 int (*qaf_audio_stream_open)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
119 audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags);
120 int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
121 int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
122 int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
123 char* (*qaf_audio_stream_get_param)(audio_stream_handle_t stream_handle, const char* key);
124 char* (*qaf_audio_session_get_param)(audio_session_handle_t handle, const char* key);
125 int (*qaf_audio_stream_start)(audio_stream_handle_t handle);
126 int (*qaf_audio_stream_stop)(audio_stream_handle_t stream_handle);
127 int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
128 int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
129 int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
130 void (*qaf_register_event_callback)(audio_session_handle_t session_handle, void *priv_data,
131 notify_event_callback_t event_callback, audio_event_id_t event_id);
132 pthread_mutex_t lock;
133 struct stream_out *stream_drain_main;
134 struct stream_out *qaf_compr_offload_out;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530135 struct stream_out *qaf_compr_offload_out_mch;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530136 struct stream_out *qaf_compr_passthrough_out;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530137 struct stream_out *qaf_passthrough_out;
138 bool hdmi_connect;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530139 int passthrough_enabled;
140 int hdmi_sink_channels;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530141 bool main_output_active;
142 bool assoc_output_active;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530143 bool qaf_msmd_enabled;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530144};
145
146static struct qaf *qaf_mod = NULL;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530147static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair) __attribute__ ((unused));
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530148
149static void lock_output_stream(struct stream_out *out)
150{
151 pthread_mutex_lock(&out->pre_lock);
152 pthread_mutex_lock(&out->lock);
153 pthread_mutex_unlock(&out->pre_lock);
154}
155
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530156static bool audio_extn_qaf_passthrough_enabled(struct stream_out *out)
157{
158 ALOGV("%s %d ", __func__, __LINE__);
159 if ((!property_get_bool("audio.qaf.reencode", false)) &&
160 property_get_bool("audio.qaf.passthrough", false)) {
161 if (property_get_bool("audio.offload.passthrough", false)) {
162 if (((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)) ||
163 ((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
164 ((out->format == AUDIO_FORMAT_DTS) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS)) ||
165 ((out->format == AUDIO_FORMAT_DTS_HD) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_DTS_HD))) {
166 return true;
167 }
168 } else {
169 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
170 return true;
171 }
172 }
173 }
174 return false;
175}
176
177static int qaf_out_callback(stream_callback_event_t event, void *param __unused, void *cookie)
178{
179 struct stream_out *out = (struct stream_out *)cookie;
180
181 out->offload_callback(event, NULL, out->offload_cookie);
182 return 0;
183}
184
185static int create_output_stream(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices, int handle_id)
186{
187 int ret = 0;
188
189 ALOGV("%s %d", __func__, __LINE__);
190 if ((handle_id == QAF_DEFAULT_PASSTHROUGH_HANDLE) &&
191 (NULL == qaf_mod->qaf_passthrough_out)) {
192 pthread_mutex_lock(&qaf_mod->lock);
193 lock_output_stream(out);
194 ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, handle_id, devices,
195 flags, config, (struct audio_stream_out **) &(qaf_mod->qaf_passthrough_out), NULL);
196 if (ret < 0) {
197 pthread_mutex_unlock(&out->lock);
198 pthread_mutex_unlock(&qaf_mod->lock);
199 ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
200 return -EINVAL;
201 }
202 qaf_mod->qaf_passthrough_out->stream.set_callback((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, (stream_callback_t) qaf_out_callback, out);
203 pthread_mutex_unlock(&out->lock);
204 pthread_mutex_unlock(&qaf_mod->lock);
205 }
206 return ret;
207}
208
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530209static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
210{
211 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
212
213 if (!cmd) {
214 ALOGE("failed to allocate mem for command 0x%x", command);
215 return -ENOMEM;
216 }
217
218 ALOGV("%s %d", __func__, command);
219
220 cmd->cmd = command;
221 list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
222 pthread_cond_signal(&out->qaf_offload_cond);
223 return 0;
224}
225
226static int audio_extn_qaf_stream_stop(struct stream_out *out)
227{
228 ALOGV("%s: %d start", __func__, __LINE__);
229 if (!qaf_mod->qaf_audio_stream_stop)
230 return -EINVAL;
231
232 return qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
233}
234
235static int qaf_out_standby(struct audio_stream *stream)
236{
237 struct stream_out *out = (struct stream_out *)stream;
238 int status = 0;
239
240 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
241 stream, out->usecase, use_case_table[out->usecase]);
242
243 lock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530244 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
245 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
246 pthread_mutex_unlock(&out->lock);
247 return status;
248 }
249 status = qaf_mod->qaf_passthrough_out->stream.common.standby((struct audio_stream *) qaf_mod->qaf_passthrough_out);
250 if (!out->standby) {
251 out->standby = true;
252 }
253 pthread_mutex_unlock(&out->lock);
254 return status;
255 }
256
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530257 if (!out->standby) {
258 out->standby = true;
259 status = audio_extn_qaf_stream_stop(out);
260 }
261 pthread_mutex_unlock(&out->lock);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530262 return status;
263}
264
265static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair)
266{
267 ALOGV("%s %d kvpair: %s", __func__, __LINE__, kv_pair);
268 if (!qaf_mod->qaf_audio_stream_set_param)
269 return -EINVAL;
270
271 return qaf_mod->qaf_audio_stream_set_param(out->qaf_stream_handle, kv_pair);
272}
273
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530274static int qaf_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
275{
276 int ret = 0;
277 ALOGVV("%s bytes = %d [%p]", __func__, bytes, out->qaf_stream_handle);
278 if (!qaf_mod->qaf_audio_stream_write)
279 return -EINVAL;
280
281 if (out->qaf_stream_handle)
282 ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
283 return ret;
284}
285
286static int qaf_out_set_volume(struct audio_stream_out *stream __unused, float left,
287 float right)
288{
289 if (qaf_mod->qaf_compr_offload_out != NULL) {
290 return qaf_mod->qaf_compr_offload_out->stream.set_volume(
291 (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out, left, right);
292 }
293 return -ENOSYS;
294}
295
296static int qaf_stream_start(struct stream_out *out)
297{
298 if (!qaf_mod->qaf_audio_stream_start)
299 return -EINVAL;
300
301 return qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
302}
303
304static int qaf_start_output_stream(struct stream_out *out)
305{
306 int ret = 0;
307 struct audio_device *adev = out->dev;
308 int snd_card_status = get_snd_card_state(adev);
309
310 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
311 ret = -EINVAL;
312 usleep(50000);
313 return ret;
314 }
315
316 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
317 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
318 out->devices);
319
320 if (SND_CARD_STATE_OFFLINE == snd_card_status) {
321 ALOGE("%s: sound card is not active/SSR returning error", __func__);
322 ret = -EIO;
323 usleep(50000);
324 return ret;
325 }
326
327 return qaf_stream_start(out);
328}
329
330static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer,
331 size_t bytes)
332{
333 struct stream_out *out = (struct stream_out *)stream;
334 struct audio_device *adev = out->dev;
335 ssize_t ret = 0;
336
337 ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
338 lock_output_stream(out);
339
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530340 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
341 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) <= 2)) {
342 ALOGD(" %s : Drop data as compress passthrough session is going on", __func__);
343 usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
344 out->stream.common.get_sample_rate(&out->stream.common));
345 goto exit;
346 }
347 ret = qaf_mod->qaf_passthrough_out->stream.write((struct audio_stream_out *)(qaf_mod->qaf_passthrough_out), buffer, bytes);
348 pthread_mutex_unlock(&out->lock);
349 return ret;
350 }
351
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530352 if (out->standby) {
353 out->standby = false;
354 pthread_mutex_lock(&adev->lock);
355 ret = qaf_start_output_stream(out);
356 pthread_mutex_unlock(&adev->lock);
357 /* ToDo: If use case is compress offload should return 0 */
358 if (ret != 0) {
359 out->standby = true;
360 goto exit;
361 }
362 }
363
364 if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
365 audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
366 adev->is_channel_status_set = true;
367 }
368
369 ret = qaf_write_input_buffer(out, buffer, bytes);
370 ALOGV("%s, ret [%d] ", __func__, (int)ret);
371 if (ret < 0) {
372 goto exit;
373 }
374 out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
375
376exit:
377
378 pthread_mutex_unlock(&out->lock);
379
380 if (ret < 0) {
381 if (ret == -EAGAIN) {
382 ALOGV("No space available in ms12 driver, post msg to cb thread");
383 lock_output_stream(out);
384 ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
385 pthread_mutex_unlock(&out->lock);
386 bytes = 0;
387 }
388 if(ret == -ENOMEM || ret == -EPERM){
389 if (out->pcm)
390 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
391 qaf_out_standby(&out->stream.common);
392 usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
393 out->stream.common.get_sample_rate(&out->stream.common));
394 }
395 }
396 return bytes;
397}
398
399static int qaf_get_timestamp(struct stream_out *out, uint64_t *frames, struct timespec *timestamp)
400{
401 int ret = 0;
402 struct str_parms *parms;
403 int value = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530404 int latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530405 int signed_frames = 0;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530406 char* kvpairs = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530407
408 ALOGV("%s out->format %d", __func__, out->format);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530409 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "get_latency");
410 if (kvpairs) {
411 parms = str_parms_create_str(kvpairs);
412 ret = str_parms_get_int(parms, "get_latency", &latency);
413 if (ret >= 0) {
414 str_parms_destroy(parms);
415 parms = NULL;
416 }
417 free(kvpairs);
418 kvpairs = NULL;
419 }
420 // MS12 Latency + Kernel Latency + Dsp Latency
421 if (qaf_mod->qaf_compr_offload_out != NULL) {
422 out->platform_latency = latency + (COMPRESS_OFFLOAD_NUM_FRAGMENTS * PCM_OFFLOAD_BUFFER_SIZE \
423 /(popcount(qaf_mod->qaf_compr_offload_out->channel_mask) * sizeof(short))) \
424 +((platform_render_latency(qaf_mod->qaf_compr_offload_out->usecase) * qaf_mod->qaf_compr_offload_out->sample_rate) / 1000000LL);
425 } else if (NULL != qaf_mod->qaf_compr_passthrough_out) {
426 out->platform_latency = latency + ((qaf_mod->qaf_compr_passthrough_out->format == AUDIO_FORMAT_AC3) ? TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DD_ENCODER_OUTPUT_SIZE) : TRANSCODE_LATENCY(COMPRESS_PASSTHROUGH_BUFFER_SIZE, DD_FRAME_SIZE, DDP_ENCODER_OUTPUT_SIZE)) \
427 + (COMPRESS_OFFLOAD_PLAYBACK_LATENCY * qaf_mod->qaf_compr_passthrough_out->sample_rate/1000);
428 }
429
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530430 if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530431 *frames = 0;
432 signed_frames = out->written - out->platform_latency;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530433 // It would be unusual for this value to be negative, but check just in case ...
434 if (signed_frames >= 0) {
435 *frames = signed_frames;
436 }
437 clock_gettime(CLOCK_MONOTONIC, timestamp);
438 } else if (qaf_mod->qaf_audio_stream_get_param) {
439 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
440 if (kvpairs) {
441 parms = str_parms_create_str(kvpairs);
442 ret = str_parms_get_int(parms, "position", &value);
443 if (ret >= 0) {
444 *frames = value;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530445 signed_frames = value - out->platform_latency;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530446 // It would be unusual for this value to be negative, but check just in case ...
447 if (signed_frames >= 0) {
448 *frames = signed_frames;
449 }
450 clock_gettime(CLOCK_MONOTONIC, timestamp);
451 }
452 str_parms_destroy(parms);
453 }
454 } else {
455 ret = -EINVAL;
456 }
457 return ret;
458}
459
460static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
461 uint64_t *frames, struct timespec *timestamp)
462{
463 struct stream_out *out = (struct stream_out *)stream;
464 int ret = -1;
465 lock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530466
467 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
468 ret = qaf_mod->qaf_passthrough_out->stream.get_presentation_position((struct audio_stream_out *)qaf_mod->qaf_passthrough_out, frames, timestamp);
469 pthread_mutex_unlock(&out->lock);
470 return ret;
471 }
472
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530473 ret = qaf_get_timestamp(out, frames, timestamp);
474 pthread_mutex_unlock(&out->lock);
475
476 return ret;
477}
478
479static int qaf_stream_pause(struct stream_out *out)
480{
481 ALOGV("%s: %d start", __func__, __LINE__);
482 if (!qaf_mod->qaf_audio_stream_pause)
483 return -EINVAL;
484
485 return qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
486}
487
488static int qaf_out_pause(struct audio_stream_out* stream)
489{
490 struct stream_out *out = (struct stream_out *)stream;
491 int status = -ENOSYS;
492 ALOGE("%s", __func__);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530493
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530494 lock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530495 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
496 status = qaf_mod->qaf_passthrough_out->stream.pause((struct audio_stream_out *) qaf_mod->qaf_passthrough_out);
497 out->offload_state = OFFLOAD_STATE_PAUSED;
498 pthread_mutex_unlock(&out->lock);
499 return status;
500 }
501
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530502 status = qaf_stream_pause(out);
503 pthread_mutex_unlock(&out->lock);
504 return status;
505}
506
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530507static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530508{
509 struct stream_out *out = (struct stream_out *)stream;
510 int status = 0;
511 ALOGV("%s stream_handle = %p , format = %x", __func__, out->qaf_stream_handle, out->format);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530512
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530513 lock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530514 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
515 status = qaf_mod->qaf_passthrough_out->stream.drain((struct audio_stream_out*)(qaf_mod->qaf_passthrough_out), type);
516 pthread_mutex_unlock(&out->lock);
517 return status;
518 }
519
520
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530521 if (out->offload_callback && out->qaf_stream_handle) {
522 /* Stream stop will trigger EOS and on EOS_EVENT received
523 from callback DRAIN_READY command is sent */
524 status = audio_extn_qaf_stream_stop(out);
525 if (out->format != AUDIO_FORMAT_PCM_16_BIT)
526 qaf_mod->stream_drain_main = out;
527 }
528 pthread_mutex_unlock(&out->lock);
529 return status;
530}
531
532static int audio_extn_qaf_stream_flush(struct stream_out *out)
533{
534 ALOGV("%s: %d exit", __func__, __LINE__);
535 if (!qaf_mod->qaf_audio_stream_flush)
536 return -EINVAL;
537
538 return qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
539}
540
541static int qaf_out_flush(struct audio_stream_out* stream)
542{
543 struct stream_out *out = (struct stream_out *)stream;
544 ALOGV("%s", __func__);
545 int status = -ENOSYS;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530546
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530547 lock_output_stream(out);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530548 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
549 status = qaf_mod->qaf_passthrough_out->stream.flush((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
550 out->offload_state = OFFLOAD_STATE_IDLE;
551 pthread_mutex_unlock(&out->lock);
552 return status;
553 }
554
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530555 status = audio_extn_qaf_stream_flush(out);
556 pthread_mutex_unlock(&out->lock);
557 ALOGV("%s Exit", __func__);
558 return status;
559}
560
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530561static uint32_t qaf_out_get_latency(const struct audio_stream_out *stream)
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530562{
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530563 struct stream_out *out = (struct stream_out *)stream;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530564 uint32_t latency = 0;
565
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530566
567 lock_output_stream(out);
568 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
569 latency = qaf_mod->qaf_passthrough_out->stream.get_latency((struct audio_stream_out *)qaf_mod->qaf_passthrough_out);
570 ALOGV("%s: latency = %u", __FUNCTION__, latency);
571 pthread_mutex_unlock(&out->lock);
572 return latency;
573 }
574 pthread_mutex_unlock(&out->lock);
575
576 if (is_offload_usecase(out->usecase)) {
577 latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
578 } else {
579 latency = PCM_OFFLOAD_PLAYBACK_LATENCY;
580 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530581 ALOGV("%s: Latency %d", __func__, latency);
582 return latency;
583}
584
585static void notify_event_callback(audio_session_handle_t session_handle __unused, void *prv_data, void *buf, audio_event_id_t event_id, int size, int device)
586{
587
588/*
589 For SPKR:
590 1. Open pcm device if device_id passed to it SPKR and write the data to pcm device
591
592 For HDMI
593 1.Open compress device for HDMI(PCM or AC3) based on current_hdmi_output_format
594 2.create offload_callback thread to receive async events
595 3.Write the data to compress device. If not all the data is consumed by the driver,
596 add a command to offload_callback thread.
597*/
598 int ret;
599 audio_output_flags_t flags;
600 struct qaf* qaf_module = (struct qaf* ) prv_data;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530601
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530602 ALOGV("%s device 0x%X, %d in event = %d", __func__, device, __LINE__, event_id);
603
604 if (event_id == AUDIO_DATA_EVENT) {
605 ALOGVV("Device id %x %s %d, bytes to written %d", device, __func__,__LINE__, size);
606
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530607 if ((qaf_mod->qaf_passthrough_out != NULL) && qaf_mod->hdmi_connect) {
608 pthread_mutex_lock(&qaf_module->lock);
609 if (qaf_mod->qaf_compr_offload_out != NULL) {
610 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
611 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
612 qaf_mod->qaf_compr_offload_out = NULL;
613 }
614 if (qaf_mod->qaf_compr_offload_out_mch) {
615 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
616 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
617 qaf_mod->qaf_compr_offload_out_mch = NULL;
618 }
619 pthread_mutex_unlock(&qaf_module->lock);
620 ALOGV("%s %d DROPPING DATA", __func__, __LINE__);
621 return;
622 } else {
623 if (qaf_mod->qaf_passthrough_out != NULL) {
624 pthread_mutex_lock(&qaf_module->lock);
625 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
626 (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
627 qaf_mod->qaf_passthrough_out = NULL;
628 qaf_mod->main_output_active = false;
629 pthread_mutex_unlock(&qaf_module->lock);
630 }
631 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530632 pthread_mutex_lock(&qaf_module->lock);
633 if ((device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD)) ||
634 (device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
635
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530636 if (NULL == qaf_mod->qaf_compr_passthrough_out && qaf_mod->hdmi_connect) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530637 struct audio_config config;
638 audio_devices_t devices;
639
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530640 if (qaf_mod->qaf_compr_offload_out_mch) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530641 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530642 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
643 qaf_mod->qaf_compr_offload_out_mch = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530644 }
645
646 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
647 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
648 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
649
650 if (device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))
651 config.format = config.offload_info.format = AUDIO_FORMAT_E_AC3;
652 else
653 config.format = config.offload_info.format = AUDIO_FORMAT_AC3;
654
655 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
656 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530657 flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530658 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
659
660 ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
661 flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_passthrough_out), NULL);
662 if (ret < 0) {
663 ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
664 pthread_mutex_unlock(&qaf_module->lock);
665 return;
666 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530667 qaf_mod->qaf_compr_passthrough_out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530668 }
669
670 if (!qaf_mod->passthrough_enabled)
671 qaf_mod->passthrough_enabled = 1;
672
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530673 if (qaf_mod->qaf_compr_passthrough_out)
674 ret = qaf_mod->qaf_compr_passthrough_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_passthrough_out, buf, size);
675 } else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL) && ((qaf_mod->hdmi_connect) &&
676 (qaf_mod->qaf_passthrough_out == NULL) && (qaf_mod->hdmi_sink_channels > 2))) {
677 if (NULL == qaf_mod->qaf_compr_offload_out_mch) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530678 struct audio_config config;
679 audio_devices_t devices;
680
681 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
682 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
683 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530684 config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530685 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530686 config.format = AUDIO_FORMAT_PCM_16_BIT;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530687 devices = AUDIO_DEVICE_NONE;
688
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530689 if (qaf_mod->hdmi_sink_channels == 8) {
690 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
691 } else if (qaf_mod->hdmi_sink_channels == 6) {
692 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530693 } else {
694 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530695 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530696 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
697 flags = AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT_PCM;
698
699 ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
700 flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_offload_out_mch), NULL);
701 if (ret < 0) {
702 ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
703 pthread_mutex_unlock(&qaf_module->lock);
704 return;
705 }
706 qaf_mod->qaf_compr_offload_out_mch->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
707 }
708
709 if (qaf_mod->qaf_compr_offload_out_mch)
710 ret = qaf_mod->qaf_compr_offload_out_mch->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_offload_out_mch, buf, size);
711 } else {
712
713 if (NULL == qaf_mod->qaf_compr_offload_out && qaf_mod->qaf_passthrough_out == NULL) {
714 struct audio_config config;
715 audio_devices_t devices;
716
717 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
718 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
719 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
720 config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
721 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
722 config.format = AUDIO_FORMAT_PCM_16_BIT;
723 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
724 devices = AUDIO_DEVICE_OUT_SPEAKER;
725 flags = AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT_PCM;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530726
727 /* TODO:: Need to Propagate errors to framework */
728 ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
729 flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_offload_out), NULL);
730 if (ret < 0) {
731 ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
732 pthread_mutex_unlock(&qaf_module->lock);
733 return;
734 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530735 qaf_mod->qaf_compr_offload_out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
736 qaf_mod->qaf_compr_offload_out->info.channel_mask = config.offload_info.channel_mask;
737 qaf_mod->qaf_compr_offload_out->info.format = config.offload_info.format;
738 qaf_mod->qaf_compr_offload_out->info.sample_rate = config.offload_info.sample_rate;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530739 }
740
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530741 if (!qaf_mod->hdmi_connect && (qaf_mod->qaf_compr_passthrough_out || qaf_mod->qaf_compr_offload_out_mch)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530742 qaf_mod->passthrough_enabled = 0;
743 if (qaf_mod->qaf_compr_passthrough_out) {
744 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
745 (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
746 qaf_mod->qaf_compr_passthrough_out = NULL;
747 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530748 if (qaf_mod->qaf_compr_offload_out_mch) {
749 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
750 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out_mch));
751 qaf_mod->qaf_compr_offload_out_mch = NULL;
752 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530753 }
754
755 /*
756 * TODO:: Since this is mixed data,
757 * need to identify to which stream the error should be sent
758 */
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530759 if (qaf_mod->qaf_compr_offload_out)
760 ret = qaf_mod->qaf_compr_offload_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_offload_out, buf, size);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530761 }
762
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530763 ALOGVV("%s:%d stream write ret = %d", __func__, __LINE__, ret);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530764 pthread_mutex_unlock(&qaf_module->lock);
765 } else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT || event_id == AUDIO_EOS_MAIN_AAC_EVENT) {
766 /* TODO:: Only MAIN Stream EOS Event is added, need to add ASSOC stream EOS Event */
767 struct stream_out *out = qaf_module->stream_drain_main;
768 if (out != NULL) {
769 lock_output_stream(out);
770 out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->offload_cookie);
771 pthread_mutex_unlock(&out->lock);
772 qaf_module->stream_drain_main = NULL;
773 ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
774 }
775 }
776 ALOGV("%s %d", __func__, __LINE__);
777}
778
779static int qaf_session_close()
780{
781 ALOGV("%s %d", __func__, __LINE__);
782 if (qaf_mod != NULL) {
783 if (!qaf_mod->qaf_audio_session_close)
784 return -EINVAL;
785
786 qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
787 qaf_mod->session_handle = NULL;
788 pthread_mutex_destroy(&qaf_mod->lock);
789 }
790 return 0;
791}
792
793static int qaf_stream_close(struct stream_out *out)
794{
795 int ret = 0;
796 ALOGV( "%s %d", __func__, __LINE__);
797 if (!qaf_mod->qaf_audio_stream_close)
798 return -EINVAL;
799 if (out->qaf_stream_handle) {
800 ALOGV( "%s %d output active flag is %x and stream handle %p", __func__, __LINE__, out->flags, out->qaf_stream_handle);
801 if ((out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) && (out->flags & AUDIO_OUTPUT_FLAG_MAIN)) { /* Close for Stream with Main and Associated Content*/
802 qaf_mod->main_output_active = false;
803 qaf_mod->assoc_output_active = false;
804 } else if (out->flags & AUDIO_OUTPUT_FLAG_MAIN) {/*Close for Main Stream*/
805 qaf_mod->main_output_active = false;
806 qaf_mod->assoc_output_active = false; /* TODO to remove resetting associated stream active flag when main stream is closed*/
807 } else if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) { /*Close for Associated Stream*/
808 qaf_mod->assoc_output_active = false;
809 } else { /*Close for Local Playback*/
810 qaf_mod->main_output_active = false;
811 }
812 ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
813 out->qaf_stream_handle = NULL;
814 }
815 ALOGV( "%s %d", __func__, __LINE__);
816 return ret;
817}
818
819static int qaf_stream_open(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices)
820{
821 int status = 0;
822 ALOGV("%s %d", __func__, __LINE__);
823
824 if (!qaf_mod->qaf_audio_stream_open)
825 return -EINVAL;
826
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530827 if (audio_extn_qaf_passthrough_enabled(out) && qaf_mod->hdmi_connect) {
828 ALOGV("%s %d passthrough is enabled", __func__, __LINE__);
829 status = create_output_stream(out, config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
830 if (status < 0) {
831 ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, status);
832 return -EINVAL;
833 }
834 return 0;
835 }
836
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530837 audio_stream_config_t input_config;
838 input_config.sample_rate = config->sample_rate;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530839 input_config.channels = popcount(config->channel_mask);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530840 input_config.format = config->format;
841
842 if ((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) {
843 input_config.format = AUDIO_FORMAT_AAC;
844 } else if((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS) {
845 input_config.format = AUDIO_FORMAT_AAC_ADTS;
846 }
847
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530848 ALOGV("%s %d audio_stream_open sample_rate(%d) channels(%d) devices(%#x) flags(%#x) format(%#x)\
849 ",__func__, __LINE__, input_config.sample_rate, input_config.channels, devices, flags, input_config.format);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530850
851 /* TODO to send appropriated flags when support for system tones is added */
852 if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
853 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_SYSTEM_TONE);
854 } else if (input_config.format == AUDIO_FORMAT_AC3 ||
855 input_config.format == AUDIO_FORMAT_E_AC3 ||
856 input_config.format == AUDIO_FORMAT_AAC ||
857 input_config.format == AUDIO_FORMAT_AAC_ADTS) {
858 if (qaf_mod->main_output_active == false) {
859 if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
860 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
861 if (status == 0) {
862 ALOGV("%s %d Open stream for Input with both Main and Associated stream contents with flag [%x] and stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
863 qaf_mod->main_output_active = true;
864 qaf_mod->assoc_output_active = true;
865 }
866 } else if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
867 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
868 if (status == 0) {
869 ALOGV("%s %d Open stream for Input with only Main flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
870 qaf_mod->main_output_active = true;
871 }
872 } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
873 ALOGE("%s %d Error main input is not active", __func__, __LINE__);
874 return -EINVAL;
875 } else {
876 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
877 if (status == 0) {
878 ALOGV("%s %d Open stream for Local playback with flag [%x] stream handle [%p] ", __func__, __LINE__, flags, out->qaf_stream_handle);
879 qaf_mod->main_output_active = true;
880 }
881 }
882 } else {
883 if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
884 ALOGE("%s %d Error main input is already active", __func__, __LINE__);
885 return -EINVAL;
886 } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
887 if (qaf_mod->assoc_output_active) {
888 ALOGE("%s %d Error assoc input is already active", __func__, __LINE__);
889 return -EINVAL;
890 } else {
891 status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
892 if (status == 0) {
893 ALOGV("%s %d Open stream for Input with only Associated flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
894 qaf_mod->assoc_output_active = true;
895 }
896 }
897 } else {
898 ALOGE("%s %d Error main input is already active", __func__, __LINE__);
899 return -EINVAL;
900 }
901 }
902 }
903
904 return status;
905}
906
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530907static int audio_extn_qaf_stream_open(struct stream_out *out)
908{
909 int status = -ENOSYS;
910 struct audio_config config;
911 audio_devices_t devices;
912
913 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
914 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
915 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
916 config.offload_info.format = out->format;
917 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
918 config.format = out->format;
919 config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
920
921 devices = AUDIO_DEVICE_OUT_SPEAKER;
922 status = qaf_stream_open(out, &config, out->flags, devices);
923 ALOGV("%s %d status %d", __func__, __LINE__, status);
924 return status;
925}
926
927static int qaf_out_resume(struct audio_stream_out* stream)
928{
929 struct stream_out *out = (struct stream_out *)stream;
930 int status = -ENOSYS;
931 ALOGV("%s", __func__);
932 lock_output_stream(out);
933 if ((!property_get_bool("audio.qaf.reencode", false)) &&
934 property_get_bool("audio.qaf.passthrough", false)) {
935 if (property_get_bool("audio.offload.passthrough", false)) {
936 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect &&
937 (((out->format == AUDIO_FORMAT_E_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_E_AC3)) ||
938 ((out->format == AUDIO_FORMAT_AC3) && platform_is_edid_supported_format(qaf_mod->adev->platform, AUDIO_FORMAT_AC3)))) {
939 status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
940 if (!status)
941 out->offload_state = OFFLOAD_STATE_PLAYING;
942 pthread_mutex_unlock(&out->lock);
943 return status;
944 } else {
945 if ((out->format == AUDIO_FORMAT_E_AC3) || (out->format == AUDIO_FORMAT_AC3)) {
946 status = audio_extn_qaf_stream_open(out);
947 if (!status)
948 out->offload_state = OFFLOAD_STATE_PLAYING;
949 out->offload_callback(STREAM_CBK_EVENT_WRITE_READY, NULL, out->offload_cookie);
950 }
951 }
952 } else {
953 if ((out->format == AUDIO_FORMAT_PCM_16_BIT) && (popcount(out->channel_mask) > 2)) {
954 if (qaf_mod->qaf_passthrough_out && qaf_mod->hdmi_connect) {
955 status = qaf_mod->qaf_passthrough_out->stream.resume((struct audio_stream_out*) qaf_mod->qaf_passthrough_out);
956 if (!status)
957 out->offload_state = OFFLOAD_STATE_PLAYING;
958 pthread_mutex_unlock(&out->lock);
959 return status;
960 }
961 }
962 }
963 }
964
965 status = qaf_stream_start(out);
966 pthread_mutex_unlock(&out->lock);
967 ALOGD("%s Exit", __func__);
968 return status;
969}
970
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530971static int qaf_deinit()
972{
973 ALOGV("%s %d", __func__, __LINE__);
974 if (qaf_mod != NULL) {
975 if (qaf_mod->qaf_compr_offload_out != NULL)
976 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
977 if (qaf_mod->qaf_compr_passthrough_out != NULL)
978 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
979
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +0530980 if (qaf_mod->qaf_passthrough_out) {
981 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
982 qaf_mod->qaf_passthrough_out = NULL;
983 }
984
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +0530985 if (qaf_mod->qaf_lib != NULL) {
986 dlclose(qaf_mod->qaf_lib);
987 qaf_mod->qaf_lib = NULL;
988 }
989 free(qaf_mod);
990 qaf_mod = NULL;
991 }
992 return 0;
993}
994
995static void *qaf_offload_thread_loop(void *context)
996{
997 struct stream_out *out = (struct stream_out *) context;
998 struct listnode *item;
999 int ret = 0;
1000 struct str_parms *parms = NULL;
1001 int value = 0;
1002 char* kvpairs = NULL;
1003
1004 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1005 set_sched_policy(0, SP_FOREGROUND);
1006 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
1007
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301008 ALOGV("%s", __func__);
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301009 lock_output_stream(out);
1010 for (;;) {
1011 struct offload_cmd *cmd = NULL;
1012 stream_callback_event_t event;
1013 bool send_callback = false;
1014
1015 ALOGV("%s qaf_offload_cmd_list %d",
1016 __func__, list_empty(&out->qaf_offload_cmd_list));
1017 if (list_empty(&out->qaf_offload_cmd_list)) {
1018 ALOGV("%s SLEEPING", __func__);
1019 pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
1020 ALOGV("%s RUNNING", __func__);
1021 continue;
1022 }
1023
1024 item = list_head(&out->qaf_offload_cmd_list);
1025 cmd = node_to_item(item, struct offload_cmd, node);
1026 list_remove(item);
1027
1028 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
1029 free(cmd);
1030 break;
1031 }
1032
1033 pthread_mutex_unlock(&out->lock);
1034 send_callback = false;
1035 switch(cmd->cmd) {
1036 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
1037 ALOGV("wait for ms12 buffer availability");
1038 while (1) {
1039 kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "buf_available");
1040 if (kvpairs) {
1041 parms = str_parms_create_str(kvpairs);
1042 ret = str_parms_get_int(parms, "buf_available", &value);
1043 if (ret >= 0) {
1044 if (value >= (int)out->compr_config.fragment_size) {
1045 ALOGV("%s buffer available", __func__);
1046 str_parms_destroy(parms);
1047 parms = NULL;
1048 break;
1049 } else {
1050 ALOGV("%s sleep", __func__);
1051 str_parms_destroy(parms);
1052 parms = NULL;
1053 usleep(10000);
1054 }
1055 }
1056 free(kvpairs);
1057 kvpairs = NULL;
1058 }
1059 }
1060 send_callback = true;
1061 event = STREAM_CBK_EVENT_WRITE_READY;
1062 break;
1063 default:
1064 ALOGV("%s unknown command received: %d", __func__, cmd->cmd);
1065 break;
1066 }
1067 lock_output_stream(out);
1068 if (send_callback && out->offload_callback) {
1069 out->offload_callback(event, NULL, out->offload_cookie);
1070 }
1071 free(cmd);
1072 }
1073
1074 while (!list_empty(&out->qaf_offload_cmd_list)) {
1075 item = list_head(&out->qaf_offload_cmd_list);
1076 list_remove(item);
1077 free(node_to_item(item, struct offload_cmd, node));
1078 }
1079 pthread_mutex_unlock(&out->lock);
1080
1081 return NULL;
1082}
1083
1084static int qaf_create_offload_callback_thread(struct stream_out *out)
1085{
1086 ALOGV("%s", __func__);
1087 pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *) NULL);
1088 list_init(&out->qaf_offload_cmd_list);
1089 pthread_create(&out->qaf_offload_thread, (const pthread_attr_t *) NULL,
1090 qaf_offload_thread_loop, out);
1091 return 0;
1092}
1093
1094static int qaf_destroy_offload_callback_thread(struct stream_out *out)
1095{
1096 ALOGV("%s", __func__);
1097 lock_output_stream(out);
1098 qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
1099 pthread_mutex_unlock(&out->lock);
1100
1101 pthread_join(out->qaf_offload_thread, (void **) NULL);
1102 pthread_cond_destroy(&out->qaf_offload_cond);
1103
1104 return 0;
1105}
1106
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301107static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
1108{
1109 struct str_parms *parms, *new_parms;
1110 char value[32];
1111 char *new_kv_pairs;
1112 int val = 0;
1113 struct stream_out *out = (struct stream_out *)stream;
1114 int ret = 0;
1115 int err = 0;
1116
1117 ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
1118 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
1119 if ((NULL != qaf_mod->qaf_compr_offload_out)) {
1120 if (qaf_mod->qaf_msmd_enabled) {
1121 if (qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect)
1122 return 1;
1123
1124 parms = str_parms_create_str(kvpairs);
1125 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
1126
1127 /* usecase : hdmi sink which supports only 2-channel pcm */
1128 if (err >= 0) {
1129 val = atoi(value);
1130 if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
1131 ((qaf_mod->hdmi_sink_channels == 2) && !(qaf_mod->passthrough_enabled))) {
1132 new_parms = str_parms_create();
1133 val |= AUDIO_DEVICE_OUT_SPEAKER;
1134 str_parms_add_int(new_parms, AUDIO_PARAMETER_STREAM_ROUTING, val);
1135 new_kv_pairs = str_parms_to_str(new_parms);
1136 qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, new_kv_pairs);
1137 free(new_kv_pairs);
1138 str_parms_destroy(new_parms);
1139 }
1140 }
1141 str_parms_destroy(parms);
1142 } else {
1143 if (!(qaf_mod->passthrough_enabled && qaf_mod->hdmi_connect))
1144 qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, kvpairs);
1145 }
1146 }
1147
1148 if (audio_extn_qaf_passthrough_enabled(out)) {
1149 parms = str_parms_create_str(kvpairs);
1150 if (!parms) {
1151 ALOGE("str_parms_create_str failed!");
1152 } else {
1153 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
1154 if (err >= 0) {
1155 val = atoi(value);
1156 if ((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
1157 (qaf_mod->qaf_passthrough_out == NULL)) {
1158 audio_output_flags_t flags;
1159 struct audio_config config;
1160 audio_devices_t devices;
1161
1162 config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
1163 config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
1164 config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
1165 config.offload_info.format = out->format;
1166 config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
1167 config.format = out->format;
1168 config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
1169
1170 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
1171 flags = out->flags;
1172
1173 if (out->qaf_stream_handle) {
1174 qaf_out_pause((struct audio_stream_out*)out);
1175 qaf_out_flush((struct audio_stream_out*)out);
1176 qaf_out_drain((struct audio_stream_out*)out, (audio_drain_type_t)STREAM_CBK_EVENT_DRAIN_READY);
1177 qaf_stream_close(out);
1178 }
1179 create_output_stream(out, &config, flags, devices, QAF_DEFAULT_PASSTHROUGH_HANDLE);
1180 qaf_mod->main_output_active = true;
1181 }
1182 }
1183 str_parms_destroy(parms);
1184 }
1185 }
1186
1187 return ret;
1188}
1189
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301190int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
1191 audio_io_handle_t handle,
1192 audio_devices_t devices,
1193 audio_output_flags_t flags,
1194 struct audio_config *config,
1195 struct audio_stream_out **stream_out,
1196 const char *address __unused)
1197{
1198 int ret = 0;
1199 struct stream_out *out;
1200
1201 ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
1202 if (*stream_out == NULL) {
1203 goto error_open;
1204 }
1205
1206 out = (struct stream_out *) *stream_out;
1207
1208 /* Override function pointers based on qaf definitions */
1209 out->stream.set_volume = qaf_out_set_volume;
1210 out->stream.pause = qaf_out_pause;
1211 out->stream.resume = qaf_out_resume;
1212 out->stream.drain = qaf_out_drain;
1213 out->stream.flush = qaf_out_flush;
1214
1215 out->stream.common.standby = qaf_out_standby;
1216 out->stream.common.set_parameters = qaf_out_set_parameters;
1217 out->stream.get_latency = qaf_out_get_latency;
1218 out->stream.write = qaf_out_write;
1219 out->stream.get_presentation_position = qaf_out_get_presentation_position;
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301220 out->platform_latency = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301221 ret = qaf_stream_open(out, config, flags, devices);
1222 if (ret < 0) {
1223 ALOGE("%s, Error opening QAF stream err[%d]!", __func__, ret);
1224 adev_close_output_stream(dev, *stream_out);
1225 goto error_open;
1226 }
1227
1228 if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
1229 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
1230 out->config.period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
1231 out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
1232 out->config.start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
1233 out->config.avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
1234 }
1235
1236 *stream_out = &out->stream;
1237 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
1238 qaf_create_offload_callback_thread(out);
1239 }
1240 ALOGV("%s: exit", __func__);
1241 return 0;
1242error_open:
1243 *stream_out = NULL;
1244 ALOGD("%s: exit: ret %d", __func__, ret);
1245 return ret;
1246}
1247
1248void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
1249 struct audio_stream_out *stream)
1250{
1251 struct stream_out *out = (struct stream_out *)stream;
1252
1253 ALOGV("%s: enter:stream_handle(%p) format = %x", __func__, out, out->format);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301254 if (qaf_mod->qaf_passthrough_out) {
1255 ALOGD("%s %d closing stream handle %p", __func__, __LINE__, qaf_mod->qaf_passthrough_out);
1256 pthread_mutex_lock(&qaf_mod->lock);
1257 adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_passthrough_out));
1258 adev_close_output_stream(dev, stream);
1259 qaf_mod->qaf_passthrough_out = NULL;
1260 qaf_mod->main_output_active = false;
1261 pthread_mutex_unlock(&qaf_mod->lock);
1262 return;
1263 }
1264
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301265 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
1266 qaf_destroy_offload_callback_thread(out);
1267 }
1268 qaf_mod->stream_drain_main = NULL;
1269 lock_output_stream(out);
1270 qaf_stream_close(out);
1271 pthread_mutex_unlock(&out->lock);
1272
1273 adev_close_output_stream(dev, stream);
1274 ALOGV("%s: exit", __func__);
1275}
1276
1277bool audio_extn_qaf_is_enabled()
1278{
1279 bool prop_enabled = false;
1280 char value[PROPERTY_VALUE_MAX] = {0};
1281 property_get("audio.qaf.enabled", value, NULL);
1282 prop_enabled = atoi(value) || !strncmp("true", value, 4);
1283 return (prop_enabled);
1284}
1285
1286int audio_extn_qaf_session_open(struct qaf *qaf_mod,
1287 device_license_config_t* lic_config)
1288{
1289 ALOGV("%s %d", __func__, __LINE__);
1290 int status = -ENOSYS;
1291
1292 pthread_mutex_init(&qaf_mod->lock, (const pthread_mutexattr_t *) NULL);
1293
1294 if (!qaf_mod->qaf_audio_session_open)
1295 return -EINVAL;
1296
1297 status = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
1298 (void *)(qaf_mod), (void *)lic_config);
1299 if(status < 0)
1300 return status;
1301
1302 if (qaf_mod->session_handle == NULL) {
1303 ALOGE("%s %d QAF wrapper session handle is NULL", __func__, __LINE__);
1304 return -ENOMEM;
1305 }
1306 if (qaf_mod->qaf_register_event_callback)
1307 qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
1308 qaf_mod, &notify_event_callback,
1309 AUDIO_DATA_EVENT);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301310
1311 if (property_get_bool("audio.qaf.msmd", false)) {
1312 qaf_mod->qaf_msmd_enabled = 1;
1313 }
1314
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301315 return status;
1316}
1317
1318char* audio_extn_qaf_stream_get_param(struct stream_out *out __unused, const char *kv_pair __unused)
1319{
1320 return NULL;
1321}
1322
1323int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
1324{
1325 int status = 0, val = 0, channels = 0;
1326 char *format_params, *kv_parirs;
1327 struct str_parms *qaf_params;
1328 char value[32];
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301329 char prop_value[PROPERTY_VALUE_MAX];
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301330 bool passth_support = false;
1331
1332 ALOGV("%s %d ", __func__, __LINE__);
1333 if (!qaf_mod || !qaf_mod->qaf_audio_session_set_param) {
1334 return -EINVAL;
1335 }
1336
1337 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
1338 if (status >= 0) {
1339 val = atoi(value);
1340 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
1341 if (property_get_bool("audio.offload.passthrough", false) &&
1342 property_get_bool("audio.qaf.reencode", false)) {
1343
1344 qaf_params = str_parms_create();
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301345 property_get("audio.qaf.hdmi.out", prop_value, NULL);
1346 if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3) &&
1347 (strncmp(prop_value, "ddp", 3) == 0)) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301348 passth_support = true;
1349 if (qaf_params) {
1350 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
1351 AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
1352 }
1353 } else if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)) {
1354 passth_support = true;
1355 if (qaf_params) {
1356 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
1357 AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
1358 }
1359 }
1360
1361 if (passth_support) {
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301362 qaf_mod->passthrough_enabled = 1;
1363 if (qaf_mod->qaf_msmd_enabled) {
1364 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1365 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
1366 } else {
1367 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1368 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
1369 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301370 format_params = str_parms_to_str(qaf_params);
1371
1372 qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
1373 }
1374 str_parms_destroy(qaf_params);
1375 }
1376
1377 if (!passth_support) {
1378 channels = platform_edid_get_max_channels(adev->platform);
1379
1380 qaf_params = str_parms_create();
1381 switch (channels) {
1382 case 8:
1383 ALOGV("%s: Switching Qaf output to 7.1 channels", __func__);
1384 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
1385 AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301386 if (qaf_mod->qaf_msmd_enabled) {
1387 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1388 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
1389 } else {
1390 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1391 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
1392 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301393 qaf_mod->hdmi_sink_channels = channels;
1394 break;
1395 case 6:
1396 ALOGV("%s: Switching Qaf output to 5.1 channels", __func__);
1397 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
1398 AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301399 if (qaf_mod->qaf_msmd_enabled) {
1400 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1401 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
1402 } else {
1403 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1404 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
1405 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301406 qaf_mod->hdmi_sink_channels = channels;
1407 break;
1408 default:
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301409 ALOGV("%s: Switching Qaf output to default channels", __func__);
1410 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
1411 AUDIO_QAF_PARAMETER_VALUE_DEFAULT_CHANNELS);
1412 if (qaf_mod->qaf_msmd_enabled) {
1413 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1414 AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI_AND_SPK);
1415 } else {
1416 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1417 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
1418 }
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301419 qaf_mod->hdmi_sink_channels = 2;
1420 break;
1421 }
1422
1423 format_params = str_parms_to_str(qaf_params);
1424 qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
1425 str_parms_destroy(qaf_params);
1426 }
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301427 qaf_mod->hdmi_connect = 1;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301428 }
1429 }
1430
1431 status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
1432 if (status >= 0) {
1433 val = atoi(value);
1434 if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
1435 qaf_params = str_parms_create();
1436 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
1437 AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
1438 str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
1439 AUDIO_QAF_PARAMETER_VALUE_PCM);
1440 qaf_mod->hdmi_sink_channels = 0;
1441
Lakshman Chaluvarajub4ec8702016-11-04 19:21:12 +05301442 qaf_mod->passthrough_enabled = 0;
1443 qaf_mod->hdmi_connect = 0;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05301444 format_params = str_parms_to_str(qaf_params);
1445 qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
1446 str_parms_destroy(qaf_params);
1447 }
1448 }
1449
1450 kv_parirs = str_parms_to_str(parms);
1451 qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, kv_parirs);
1452
1453 return status;
1454}
1455
1456char* audio_extn_qaf_get_param(struct audio_device *adev __unused, const char *kv_pair __unused)
1457{
1458 return 0;
1459}
1460
1461int audio_extn_qaf_init(struct audio_device *adev)
1462{
1463 char value[PROPERTY_VALUE_MAX] = {0};
1464 char lib_name[PROPERTY_VALUE_MAX] = {0};
1465 unsigned char* license_data = NULL;
1466 device_license_config_t* lic_config = NULL;
1467 ALOGV("%s %d", __func__, __LINE__);
1468 int ret = 0, size = 0;
1469
1470 qaf_mod = malloc(sizeof(struct qaf));
1471 if(qaf_mod == NULL) {
1472 ALOGE("%s, out of memory", __func__);
1473 ret = -ENOMEM;
1474 goto done;
1475 }
1476 memset(qaf_mod, 0, sizeof(struct qaf));
1477 lic_config = (device_license_config_t*) calloc(1, sizeof(device_license_config_t));
1478 if(lic_config == NULL) {
1479 ALOGE("%s, out of memory", __func__);
1480 ret = -ENOMEM;
1481 goto done;
1482 }
1483 qaf_mod->adev = adev;
1484 property_get("audio.qaf.library", value, NULL);
1485 snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
1486
1487 license_data = platform_get_license((struct audio_hw_device *)(qaf_mod->adev->platform), &size);
1488 if (!license_data) {
1489 ALOGE("License is not present");
1490 ret = -EINVAL;
1491 goto done;
1492 }
1493 lic_config->p_license = (unsigned char* ) calloc(1, size);
1494 if(lic_config->p_license == NULL) {
1495 ALOGE("%s, out of memory", __func__);
1496 ret = -ENOMEM;
1497 goto done;
1498 }
1499 lic_config->l_size = size;
1500 memcpy(lic_config->p_license, license_data, size);
1501
1502 if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
1503 lic_config->manufacturer_id = (unsigned long) atoi (value);
1504 } else {
1505 ALOGE("audio.qaf.manufacturer id is not set");
1506 ret = -EINVAL;
1507 goto done;
1508 }
1509
1510 ret = audio_extn_qaf_session_open(qaf_mod, lic_config);
1511done:
1512 if (license_data != NULL) {
1513 free(license_data);
1514 license_data = NULL;
1515 }
1516 if (lic_config->p_license != NULL) {
1517 free(lic_config->p_license);
1518 lic_config->p_license = NULL;
1519 }
1520 if (lic_config != NULL) {
1521 free(lic_config);
1522 lic_config = NULL;
1523 }
1524 if (ret != 0) {
1525 if (qaf_mod != NULL) {
1526 free(qaf_mod);
1527 qaf_mod = NULL;
1528 }
1529 }
1530 return ret;
1531}
1532
1533void audio_extn_qaf_deinit()
1534{
1535 qaf_session_close();
1536 qaf_deinit();
1537}