1/*
2 * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved.
3 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#define LOG_TAG "audio_hw_compress"
21/*#define LOG_NDEBUG 0*/
22#define LOG_NDDEBUG 0
23
24#include <errno.h>
25#include <cutils/properties.h>
26#include <stdlib.h>
27#include <dlfcn.h>
28#include <cutils/str_parms.h>
29#include <cutils/log.h>
30
31#include "audio_hw.h"
32#include "platform.h"
33#include "platform_api.h"
34
35#include "sound/compress_params.h"
36#include "sound/compress_offload.h"
37
38#ifdef COMPRESS_CAPTURE_ENABLED
39
40#define COMPRESS_IN_CONFIG_CHANNELS 1
41#define COMPRESS_IN_CONFIG_PERIOD_SIZE 2048
42#define COMPRESS_IN_CONFIG_PERIOD_COUNT 16
43
44
45struct compress_in_module {
46    uint8_t             *in_buf;
47};
48
49static struct compress_in_module c_in_mod = {
50    .in_buf = NULL,
51};
52
53
54void audio_extn_compr_cap_init(struct stream_in *in)
55{
56    in->usecase = USECASE_AUDIO_RECORD_COMPRESS;
57    in->config.channels = COMPRESS_IN_CONFIG_CHANNELS;
58    in->config.period_size = COMPRESS_IN_CONFIG_PERIOD_SIZE;
59    in->config.period_count= COMPRESS_IN_CONFIG_PERIOD_COUNT;
60    in->config.format = AUDIO_FORMAT_AMR_WB;
61    c_in_mod.in_buf = (uint8_t*)calloc(1, in->config.period_size*2);
62}
63
64void audio_extn_compr_cap_deinit()
65{
66    if (c_in_mod.in_buf) {
67        free(c_in_mod.in_buf);
68        c_in_mod.in_buf = NULL;
69    }
70}
71
72bool audio_extn_compr_cap_enabled()
73{
74    char prop_value[PROPERTY_VALUE_MAX] = {0};
75    bool tunnel_encode = false;
76
77    property_get("tunnel.audio.encode",prop_value,"0");
78    if (!strncmp("true", prop_value, sizeof("true")))
79        return true;
80    else
81        return false;
82}
83
84bool audio_extn_compr_cap_format_supported(audio_format_t format)
85{
86    if (format == AUDIO_FORMAT_AMR_WB)
87        return true;
88    else
89        return false;
90}
91
92
93bool audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase)
94{
95    if ((usecase == USECASE_AUDIO_RECORD_COMPRESS) ||
96        (usecase == USECASE_INCALL_REC_UPLINK_COMPRESS) ||
97        (usecase == USECASE_INCALL_REC_DOWNLINK_COMPRESS) ||
98        (usecase == USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS))
99        return true;
100    else
101        return false;
102}
103
104
105size_t audio_extn_compr_cap_get_buffer_size(audio_format_t format)
106{
107    if (format == AUDIO_FORMAT_AMR_WB)
108        /*One AMR WB frame is 61 bytes. Return that to the caller.
109        The buffer size is not altered, that is still period size.*/
110        return AMR_WB_FRAMESIZE;
111    else
112        return 0;
113}
114
115size_t audio_extn_compr_cap_read(struct stream_in * in,
116    void *buffer, size_t bytes)
117{
118    int ret;
119    struct snd_compr_audio_info *header;
120    uint32_t c_in_header;
121    uint32_t c_in_buf_size;
122
123    c_in_buf_size = in->config.period_size*2;
124
125    if (in->pcm) {
126        ret = pcm_read(in->pcm, c_in_mod.in_buf, c_in_buf_size);
127        if (ret < 0) {
128            ALOGE("pcm_read() returned failure: %d", ret);
129            return ret;
130        } else {
131            header = (struct snd_compr_audio_info *) c_in_mod.in_buf;
132            c_in_header = sizeof(*header) + header->reserved[0];
133            if (header->frame_size > 0) {
134                if (c_in_header  + header->frame_size > c_in_buf_size) {
135                    ALOGW("AMR WB read buffer overflow.");
136                    header->frame_size =
137                        bytes - sizeof(*header) - header->reserved[0];
138                }
139                ALOGV("c_in_buf: %p, data offset: %p, header size: %zu,"
140                    "reserved[0]: %u frame_size: %d", c_in_mod.in_buf,
141                        c_in_mod.in_buf + c_in_header,
142                        sizeof(*header), header->reserved[0],
143                        header->frame_size);
144                memcpy(buffer, c_in_mod.in_buf + c_in_header, header->frame_size);
145            } else {
146                ALOGE("pcm_read() with zero frame size");
147                ret = -EINVAL;
148            }
149        }
150    }
151
152    return 0;
153}
154
155#endif /* COMPRESS_CAPTURE_ENABLED end */
156