• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "a2dp_opus_decoder"
18 
19 #include "a2dp_vendor_opus_decoder.h"
20 
21 #include <base/logging.h>
22 #include <opus.h>
23 
24 #include "a2dp_vendor_opus.h"
25 #include "osi/include/allocator.h"
26 #include "osi/include/log.h"
27 
28 typedef struct {
29   OpusDecoder* opus_handle = nullptr;
30   bool has_opus_handle;
31   int16_t* decode_buf = nullptr;
32   decoded_data_callback_t decode_callback;
33 } tA2DP_OPUS_DECODER_CB;
34 
35 static tA2DP_OPUS_DECODER_CB a2dp_opus_decoder_cb;
36 
a2dp_vendor_opus_decoder_cleanup(void)37 void a2dp_vendor_opus_decoder_cleanup(void) {
38   if (a2dp_opus_decoder_cb.has_opus_handle) {
39     osi_free(a2dp_opus_decoder_cb.opus_handle);
40 
41     if (a2dp_opus_decoder_cb.decode_buf != nullptr) {
42       memset(a2dp_opus_decoder_cb.decode_buf, 0,
43              A2DP_OPUS_DECODE_BUFFER_LENGTH);
44       osi_free(a2dp_opus_decoder_cb.decode_buf);
45       a2dp_opus_decoder_cb.decode_buf = nullptr;
46     }
47     a2dp_opus_decoder_cb.has_opus_handle = false;
48   }
49 
50   return;
51 }
52 
a2dp_vendor_opus_decoder_init(decoded_data_callback_t decode_callback)53 bool a2dp_vendor_opus_decoder_init(decoded_data_callback_t decode_callback) {
54   a2dp_vendor_opus_decoder_cleanup();
55 
56   int32_t err_val = OPUS_OK;
57   int32_t size = 0;
58 
59   size = opus_decoder_get_size(A2DP_OPUS_CODEC_OUTPUT_CHS);
60   a2dp_opus_decoder_cb.opus_handle =
61       static_cast<OpusDecoder*>(osi_malloc(size));
62   if (a2dp_opus_decoder_cb.opus_handle == nullptr) {
63     LOG_ERROR("failed to allocate opus decoder handle");
64     return false;
65   }
66   err_val = opus_decoder_init(a2dp_opus_decoder_cb.opus_handle,
67                               A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE,
68                               A2DP_OPUS_CODEC_OUTPUT_CHS);
69   if (err_val == OPUS_OK) {
70     a2dp_opus_decoder_cb.has_opus_handle = true;
71 
72     a2dp_opus_decoder_cb.decode_buf =
73         static_cast<int16_t*>(osi_malloc(A2DP_OPUS_DECODE_BUFFER_LENGTH));
74 
75     memset(a2dp_opus_decoder_cb.decode_buf, 0, A2DP_OPUS_DECODE_BUFFER_LENGTH);
76 
77     a2dp_opus_decoder_cb.decode_callback = decode_callback;
78     LOG_INFO("decoder init success");
79     return true;
80   } else {
81     LOG_ERROR("failed to initialize Opus Decoder");
82     a2dp_opus_decoder_cb.has_opus_handle = false;
83     return false;
84   }
85 
86   return false;
87 }
88 
a2dp_vendor_opus_decoder_configure(const uint8_t * p_codec_info)89 void a2dp_vendor_opus_decoder_configure(const uint8_t* p_codec_info) { return; }
90 
a2dp_vendor_opus_decoder_decode_packet(BT_HDR * p_buf)91 bool a2dp_vendor_opus_decoder_decode_packet(BT_HDR* p_buf) {
92   uint32_t frameSize;
93   uint32_t numChannels;
94   uint32_t numFrames;
95   int32_t ret_val = 0;
96   uint32_t frameLen = 0;
97 
98   if (p_buf == nullptr) {
99     LOG_ERROR("Dropping packet with nullptr");
100     return false;
101   }
102 
103   if (p_buf->len == 0) {
104     LOG_ERROR("Empty packet");
105     return false;
106   }
107 
108   auto* pBuffer =
109       reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset + 1);
110   int32_t bufferSize = p_buf->len - 1;
111 
112   numChannels = opus_packet_get_nb_channels(pBuffer);
113   numFrames = opus_packet_get_nb_frames(pBuffer, bufferSize);
114   frameSize = opus_packet_get_samples_per_frame(
115       pBuffer, A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE);
116   frameLen = opus_packet_get_nb_samples(pBuffer, bufferSize,
117                                         A2DP_OPUS_CODEC_DEFAULT_SAMPLERATE);
118   uint32_t num_frames = pBuffer[0] & 0xf;
119 
120   LOG_ERROR("numframes %d framesize %d framelen %d bufferSize %d", num_frames,
121             frameSize, frameLen, bufferSize);
122   LOG_ERROR("numChannels %d numFrames %d offset %d", numChannels, numFrames,
123             p_buf->offset);
124 
125   for (uint32_t frame = 0; frame < numFrames; ++frame) {
126     {
127       numChannels = opus_packet_get_nb_channels(pBuffer);
128 
129       ret_val = opus_decode(a2dp_opus_decoder_cb.opus_handle,
130                             reinterpret_cast<unsigned char*>(pBuffer),
131                             bufferSize, a2dp_opus_decoder_cb.decode_buf,
132                             A2DP_OPUS_DECODE_BUFFER_LENGTH, 0 /* flags */);
133 
134       if (ret_val < OPUS_OK) {
135         LOG_ERROR("Opus DecodeFrame failed %d, applying concealment", ret_val);
136         ret_val = opus_decode(a2dp_opus_decoder_cb.opus_handle, NULL, 0,
137                               a2dp_opus_decoder_cb.decode_buf,
138                               A2DP_OPUS_DECODE_BUFFER_LENGTH, 0 /* flags */);
139       }
140 
141       size_t frame_len =
142           ret_val * numChannels * sizeof(a2dp_opus_decoder_cb.decode_buf[0]);
143       a2dp_opus_decoder_cb.decode_callback(
144           reinterpret_cast<uint8_t*>(a2dp_opus_decoder_cb.decode_buf),
145           frame_len);
146     }
147   }
148   return true;
149 }
150 
a2dp_vendor_opus_decoder_start(void)151 void a2dp_vendor_opus_decoder_start(void) { return; }
152 
a2dp_vendor_opus_decoder_suspend(void)153 void a2dp_vendor_opus_decoder_suspend(void) {
154   int32_t err_val = 0;
155 
156   if (a2dp_opus_decoder_cb.has_opus_handle) {
157     err_val =
158         opus_decoder_ctl(a2dp_opus_decoder_cb.opus_handle, OPUS_RESET_STATE);
159     if (err_val != OPUS_OK) {
160       LOG_ERROR("failed to reset decoder");
161     }
162   }
163   return;
164 }
165