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 
45 struct compress_in_module {
46     uint8_t             *in_buf;
47 };
48 
49 static struct compress_in_module c_in_mod = {
50     .in_buf = NULL,
51 };
52 
53 
audio_extn_compr_cap_init(struct stream_in * in)54 void 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 
audio_extn_compr_cap_deinit()64 void 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 
audio_extn_compr_cap_enabled()72 bool 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 
audio_extn_compr_cap_format_supported(audio_format_t format)84 bool 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 
audio_extn_compr_cap_usecase_supported(audio_usecase_t usecase)93 bool 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 
audio_extn_compr_cap_get_buffer_size(audio_format_t format)105 size_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 
audio_extn_compr_cap_read(struct stream_in * in,void * buffer,size_t bytes)115 size_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