xref: /aosp_15_r20/frameworks/av/media/libstagefright/codecs/opus/dec/SoftOpus.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2014 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_NDEBUG 0
18 #define LOG_TAG "SoftOpus"
19 #include <utils/Log.h>
20 
21 #include "SoftOpus.h"
22 #include <OMX_AudioExt.h>
23 #include <OMX_IndexExt.h>
24 
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/MediaDefs.h>
27 
28 extern "C" {
29     #include <opus.h>
30     #include <opus_multistream.h>
31 }
32 
33 namespace android {
34 
35 static const int kRate = 48000;
36 
37 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
38 // mappings for up to 8 channels. This information is part of the Vorbis I
39 // Specification:
40 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
41 static const int kMaxChannels = 8;
42 
43 template<class T>
InitOMXParams(T * params)44 static void InitOMXParams(T *params) {
45     params->nSize = sizeof(T);
46     params->nVersion.s.nVersionMajor = 1;
47     params->nVersion.s.nVersionMinor = 0;
48     params->nVersion.s.nRevision = 0;
49     params->nVersion.s.nStep = 0;
50 }
51 
SoftOpus(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)52 SoftOpus::SoftOpus(
53         const char *name,
54         const OMX_CALLBACKTYPE *callbacks,
55         OMX_PTR appData,
56         OMX_COMPONENTTYPE **component)
57     : SimpleSoftOMXComponent(name, callbacks, appData, component),
58       mInputBufferCount(0),
59       mDecoder(NULL),
60       mHeader(NULL),
61       mNumChannels(1),
62       mSamplingRate(kRate),
63       mCodecDelay(0),
64       mSeekPreRoll(0),
65       mAnchorTimeUs(0),
66       mNumFramesOutput(0),
67       mHaveEOS(false),
68       mOutputPortSettingsChange(NONE) {
69     initPorts();
70     CHECK_EQ(initDecoder(), (status_t)OK);
71 }
72 
~SoftOpus()73 SoftOpus::~SoftOpus() {
74     if (mDecoder != NULL) {
75         opus_multistream_decoder_destroy(mDecoder);
76         mDecoder = NULL;
77     }
78     if (mHeader != NULL) {
79         delete mHeader;
80         mHeader = NULL;
81     }
82 }
83 
initPorts()84 void SoftOpus::initPorts() {
85     OMX_PARAM_PORTDEFINITIONTYPE def;
86     InitOMXParams(&def);
87 
88     def.nPortIndex = 0;
89     def.eDir = OMX_DirInput;
90     def.nBufferCountMin = kNumBuffers;
91     def.nBufferCountActual = def.nBufferCountMin;
92     def.nBufferSize = 960 * 6;
93     def.bEnabled = OMX_TRUE;
94     def.bPopulated = OMX_FALSE;
95     def.eDomain = OMX_PortDomainAudio;
96     def.bBuffersContiguous = OMX_FALSE;
97     def.nBufferAlignment = 1;
98 
99     def.format.audio.cMIMEType =
100         const_cast<char *>(MEDIA_MIMETYPE_AUDIO_OPUS);
101 
102     def.format.audio.pNativeRender = NULL;
103     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
104     def.format.audio.eEncoding =
105         (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS;
106 
107     addPort(def);
108 
109     def.nPortIndex = 1;
110     def.eDir = OMX_DirOutput;
111     def.nBufferCountMin = kNumBuffers;
112     def.nBufferCountActual = def.nBufferCountMin;
113     def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t) * kMaxChannels;
114     def.bEnabled = OMX_TRUE;
115     def.bPopulated = OMX_FALSE;
116     def.eDomain = OMX_PortDomainAudio;
117     def.bBuffersContiguous = OMX_FALSE;
118     def.nBufferAlignment = 2;
119 
120     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
121     def.format.audio.pNativeRender = NULL;
122     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
123     def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
124 
125     addPort(def);
126 }
127 
initDecoder()128 status_t SoftOpus::initDecoder() {
129     return OK;
130 }
131 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)132 OMX_ERRORTYPE SoftOpus::internalGetParameter(
133         OMX_INDEXTYPE index, OMX_PTR params) {
134     switch ((int)index) {
135         case OMX_IndexParamAudioPortFormat:
136         {
137             OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
138                 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
139 
140             if (!isValidOMXParam(formatParams)) {
141                 return OMX_ErrorBadParameter;
142             }
143 
144             if (formatParams->nPortIndex > 1) {
145                 return OMX_ErrorUndefined;
146             }
147 
148             if (formatParams->nIndex > 0) {
149                 return OMX_ErrorNoMore;
150             }
151 
152             formatParams->eEncoding =
153                 (formatParams->nPortIndex == 0)
154                     ? (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS :
155                        OMX_AUDIO_CodingPCM;
156 
157             return OMX_ErrorNone;
158         }
159 
160         case OMX_IndexParamAudioAndroidOpus:
161         {
162             OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
163                 (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
164 
165             if (!isValidOMXParam(opusParams)) {
166                 return OMX_ErrorBadParameter;
167             }
168 
169             if (opusParams->nPortIndex != 0) {
170                 return OMX_ErrorUndefined;
171             }
172 
173             opusParams->nAudioBandWidth = 0;
174             opusParams->nSampleRate = mSamplingRate;
175             opusParams->nBitRate = 0;
176 
177             if (!isConfigured()) {
178                 opusParams->nChannels = mNumChannels;
179             } else {
180                 opusParams->nChannels = mHeader->channels;
181             }
182 
183             return OMX_ErrorNone;
184         }
185 
186         case OMX_IndexParamAudioPcm:
187         {
188             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
189                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
190 
191             if (!isValidOMXParam(pcmParams)) {
192                 return OMX_ErrorBadParameter;
193             }
194 
195             if (pcmParams->nPortIndex != 1) {
196                 return OMX_ErrorUndefined;
197             }
198 
199             pcmParams->eNumData = OMX_NumericalDataSigned;
200             pcmParams->eEndian = OMX_EndianBig;
201             pcmParams->bInterleaved = OMX_TRUE;
202             pcmParams->nBitPerSample = 16;
203             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
204             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
205             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
206             pcmParams->nSamplingRate = kRate;
207 
208             if (!isConfigured()) {
209                 pcmParams->nChannels = 1;
210             } else {
211                 pcmParams->nChannels = mHeader->channels;
212             }
213 
214             return OMX_ErrorNone;
215         }
216 
217         default:
218             return SimpleSoftOMXComponent::internalGetParameter(index, params);
219     }
220 }
221 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)222 OMX_ERRORTYPE SoftOpus::internalSetParameter(
223         OMX_INDEXTYPE index, const OMX_PTR params) {
224     switch ((int)index) {
225         case OMX_IndexParamStandardComponentRole:
226         {
227             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
228                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
229 
230             if (!isValidOMXParam(roleParams)) {
231                 return OMX_ErrorBadParameter;
232             }
233 
234             if (strncmp((const char *)roleParams->cRole,
235                         "audio_decoder.opus",
236                         OMX_MAX_STRINGNAME_SIZE - 1)) {
237                 return OMX_ErrorUndefined;
238             }
239 
240             return OMX_ErrorNone;
241         }
242 
243         case OMX_IndexParamAudioPortFormat:
244         {
245             const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
246                 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
247 
248             if (!isValidOMXParam(formatParams)) {
249                 return OMX_ErrorBadParameter;
250             }
251 
252             if (formatParams->nPortIndex > 1) {
253                 return OMX_ErrorUndefined;
254             }
255 
256             if ((formatParams->nPortIndex == 0
257                         && formatParams->eEncoding !=
258                            (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS)
259                 || (formatParams->nPortIndex == 1
260                         && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
261                 return OMX_ErrorUndefined;
262             }
263 
264             return OMX_ErrorNone;
265         }
266 
267         case OMX_IndexParamAudioAndroidOpus:
268         {
269             const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
270                 (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
271 
272             if (!isValidOMXParam(opusParams)) {
273                 return OMX_ErrorBadParameter;
274             }
275 
276             if (opusParams->nPortIndex != 0) {
277                 return OMX_ErrorUndefined;
278             }
279             mNumChannels = opusParams->nChannels;
280             mSamplingRate = opusParams->nSampleRate;
281             return OMX_ErrorNone;
282         }
283 
284         default:
285             return SimpleSoftOMXComponent::internalSetParameter(index, params);
286     }
287 }
288 
isConfigured() const289 bool SoftOpus::isConfigured() const {
290     return mInputBufferCount >= 1;
291 }
292 
ReadLE16(const uint8_t * data,size_t data_size,uint32_t read_offset)293 static uint16_t ReadLE16(const uint8_t *data, size_t data_size,
294                          uint32_t read_offset) {
295     if (read_offset + 1 > data_size)
296         return 0;
297     uint16_t val;
298     val = data[read_offset];
299     val |= data[read_offset + 1] << 8;
300     return val;
301 }
302 
303 // Maximum packet size used in Xiph's opusdec.
304 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
305 
306 // Default audio output channel layout. Used to initialize |stream_map| in
307 // OpusHeader, and passed to opus_multistream_decoder_create() when the header
308 // does not contain mapping information. The values are valid only for mono and
309 // stereo output: Opus streams with more than 2 channels require a stream map.
310 static const int kMaxChannelsWithDefaultLayout = 2;
311 static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
312 
313 // Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
ParseOpusHeader(const uint8_t * data,size_t data_size,OpusHeader * header)314 static bool ParseOpusHeader(const uint8_t *data, size_t data_size,
315                             OpusHeader* header) {
316     // Size of the Opus header excluding optional mapping information.
317     const size_t kOpusHeaderSize = 19;
318 
319     // Offset to the channel count byte in the Opus header.
320     const size_t kOpusHeaderChannelsOffset = 9;
321 
322     // Offset to the pre-skip value in the Opus header.
323     const size_t kOpusHeaderSkipSamplesOffset = 10;
324 
325     // Offset to the gain value in the Opus header.
326     const size_t kOpusHeaderGainOffset = 16;
327 
328     // Offset to the channel mapping byte in the Opus header.
329     const size_t kOpusHeaderChannelMappingOffset = 18;
330 
331     // Opus Header contains a stream map. The mapping values are in the header
332     // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
333     // data contains stream count, coupling information, and per channel mapping
334     // values:
335     //   - Byte 0: Number of streams.
336     //   - Byte 1: Number coupled.
337     //   - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
338     //             values.
339     const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
340     const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
341     const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
342 
343     if (data_size < kOpusHeaderSize) {
344         ALOGV("Header size is too small.");
345         return false;
346     }
347     header->channels = *(data + kOpusHeaderChannelsOffset);
348 
349     if (header->channels <= 0 || header->channels > kMaxChannels) {
350         ALOGV("Invalid Header, wrong channel count: %d", header->channels);
351         return false;
352     }
353     header->skip_samples = ReadLE16(data, data_size,
354                                         kOpusHeaderSkipSamplesOffset);
355     header->gain_db = static_cast<int16_t>(
356                               ReadLE16(data, data_size,
357                                        kOpusHeaderGainOffset));
358     header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
359     if (!header->channel_mapping) {
360         if (header->channels > kMaxChannelsWithDefaultLayout) {
361             ALOGV("Invalid Header, missing stream map.");
362             return false;
363         }
364         header->num_streams = 1;
365         header->num_coupled = header->channels > 1;
366         header->stream_map[0] = 0;
367         header->stream_map[1] = 1;
368         return true;
369     }
370     if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
371         ALOGV("Invalid stream map; insufficient data for current channel "
372               "count: %d", header->channels);
373         return false;
374     }
375     header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
376     header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
377     if (header->num_streams + header->num_coupled != header->channels) {
378         ALOGV("Inconsistent channel mapping.");
379         return false;
380     }
381     for (int i = 0; i < header->channels; ++i)
382       header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
383     return true;
384 }
385 
386 // Convert nanoseconds to number of samples.
ns_to_samples(uint64_t ns,int kRate)387 static uint64_t ns_to_samples(uint64_t ns, int kRate) {
388     return static_cast<double>(ns) * kRate / 1000000000;
389 }
390 
handleEOS()391 void SoftOpus::handleEOS() {
392     List<BufferInfo *> &inQueue = getPortQueue(0);
393     List<BufferInfo *> &outQueue = getPortQueue(1);
394     CHECK(!inQueue.empty() && !outQueue.empty());
395 
396     BufferInfo *outInfo = *outQueue.begin();
397     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
398     outHeader->nFilledLen = 0;
399     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
400     mHaveEOS = true;
401 
402     outQueue.erase(outQueue.begin());
403     outInfo->mOwnedByUs = false;
404     notifyFillBufferDone(outHeader);
405 
406     BufferInfo *inInfo = *inQueue.begin();
407     OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
408     inQueue.erase(inQueue.begin());
409     inInfo->mOwnedByUs = false;
410     notifyEmptyBufferDone(inHeader);
411 
412     ++mInputBufferCount;
413 }
414 
onQueueFilled(OMX_U32)415 void SoftOpus::onQueueFilled(OMX_U32 /* portIndex */) {
416     List<BufferInfo *> &inQueue = getPortQueue(0);
417     List<BufferInfo *> &outQueue = getPortQueue(1);
418 
419     if (mOutputPortSettingsChange != NONE) {
420         return;
421     }
422 
423     while (!mHaveEOS && !inQueue.empty() && !outQueue.empty()) {
424         BufferInfo *inInfo = *inQueue.begin();
425         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
426 
427         if (mInputBufferCount < 3) {
428             const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
429             size_t size = inHeader->nFilledLen;
430 
431             if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) {
432                 handleEOS();
433                 return;
434             }
435 
436             if (size < sizeof(int64_t)) {
437                 // The 2nd and 3rd input buffer are expected to contain
438                 //  an int64_t (see below), so make sure we get at least
439                 //  that much. The first input buffer must contain 19 bytes,
440                 //  but that is checked already.
441                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
442                 return;
443             }
444 
445             if (mInputBufferCount == 0) {
446                 delete mHeader;
447                 mHeader = new OpusHeader();
448                 memset(mHeader, 0, sizeof(*mHeader));
449                 if (!ParseOpusHeader(data, size, mHeader)) {
450                     ALOGV("Parsing Opus Header failed.");
451                     notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
452                     return;
453                 }
454 
455                 uint8_t channel_mapping[kMaxChannels] = {0};
456                 if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
457                     memcpy(&channel_mapping,
458                            kDefaultOpusChannelLayout,
459                            kMaxChannelsWithDefaultLayout);
460                 } else {
461                     memcpy(&channel_mapping,
462                            mHeader->stream_map,
463                            mHeader->channels);
464                 }
465 
466                 int status = OPUS_INVALID_STATE;
467                 if (mDecoder != NULL) {
468                     opus_multistream_decoder_destroy(mDecoder);
469                 }
470                 mDecoder = opus_multistream_decoder_create(kRate,
471                                                            mHeader->channels,
472                                                            mHeader->num_streams,
473                                                            mHeader->num_coupled,
474                                                            channel_mapping,
475                                                            &status);
476                 if (!mDecoder || status != OPUS_OK) {
477                     ALOGV("opus_multistream_decoder_create failed status=%s",
478                           opus_strerror(status));
479                     notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
480                     return;
481                 }
482                 status =
483                     opus_multistream_decoder_ctl(mDecoder,
484                                                  OPUS_SET_GAIN(mHeader->gain_db));
485                 if (status != OPUS_OK) {
486                     ALOGV("Failed to set OPUS header gain; status=%s",
487                           opus_strerror(status));
488                     notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
489                     return;
490                 }
491             } else if (mInputBufferCount == 1) {
492                 mCodecDelay = ns_to_samples(
493                                   *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
494                                                                inHeader->nOffset)),
495                                   kRate);
496                 mSamplesToDiscard = mCodecDelay;
497             } else {
498                 mSeekPreRoll = ns_to_samples(
499                                    *(reinterpret_cast<int64_t*>(inHeader->pBuffer +
500                                                                 inHeader->nOffset)),
501                                    kRate);
502                 mSamplingRate = kRate;
503                 mNumChannels = mHeader->channels;
504                 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
505                 mOutputPortSettingsChange = AWAITING_DISABLED;
506             }
507 
508             if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
509                 handleEOS();
510                 return;
511             }
512 
513             inQueue.erase(inQueue.begin());
514             inInfo->mOwnedByUs = false;
515             notifyEmptyBufferDone(inHeader);
516             ++mInputBufferCount;
517 
518             continue;
519         }
520 
521         // Ignore CSD re-submissions.
522         if (mInputBufferCount >= 3 && (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
523             if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
524                 handleEOS();
525                 return;
526             }
527 
528             inQueue.erase(inQueue.begin());
529             inInfo->mOwnedByUs = false;
530             notifyEmptyBufferDone(inHeader);
531             continue;
532         }
533 
534         BufferInfo *outInfo = *outQueue.begin();
535         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
536 
537         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
538             handleEOS();
539             return;
540         }
541 
542         if (inHeader->nOffset == 0) {
543             mAnchorTimeUs = inHeader->nTimeStamp;
544             mNumFramesOutput = 0;
545         }
546 
547         // When seeking to zero, |mCodecDelay| samples has to be discarded
548         // instead of |mSeekPreRoll| samples (as we would when seeking to any
549         // other timestamp).
550         if (inHeader->nTimeStamp == 0) {
551             mSamplesToDiscard = mCodecDelay;
552         }
553 
554         const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
555         const uint32_t size = inHeader->nFilledLen;
556         size_t frameSize = kMaxOpusOutputPacketSizeSamples;
557         if (frameSize > outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels) {
558             frameSize = outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels;
559             android_errorWriteLog(0x534e4554, "27833616");
560         }
561 
562         int numFrames = opus_multistream_decode(mDecoder,
563                                                 data,
564                                                 size,
565                                                 (int16_t *)outHeader->pBuffer,
566                                                 frameSize,
567                                                 0);
568         if (numFrames < 0) {
569             ALOGE("opus_multistream_decode returned %d", numFrames);
570             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
571             return;
572         }
573 
574         outHeader->nOffset = 0;
575         if (mSamplesToDiscard > 0) {
576             if (mSamplesToDiscard > numFrames) {
577                 mSamplesToDiscard -= numFrames;
578                 numFrames = 0;
579             } else {
580                 numFrames -= mSamplesToDiscard;
581                 outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) *
582                                      mHeader->channels;
583                 mSamplesToDiscard = 0;
584             }
585         }
586 
587         outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
588 
589         outHeader->nTimeStamp = mAnchorTimeUs +
590                                 (mNumFramesOutput * 1000000LL) /
591                                 kRate;
592 
593         mNumFramesOutput += numFrames;
594 
595         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
596             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
597             mHaveEOS = true;
598         } else {
599             outHeader->nFlags = 0;
600         }
601 
602         inInfo->mOwnedByUs = false;
603         inQueue.erase(inQueue.begin());
604         notifyEmptyBufferDone(inHeader);
605         ++mInputBufferCount;
606 
607         outInfo->mOwnedByUs = false;
608         outQueue.erase(outQueue.begin());
609         notifyFillBufferDone(outHeader);
610     }
611 }
612 
onPortFlushCompleted(OMX_U32 portIndex)613 void SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) {
614     if (portIndex == 0 && mDecoder != NULL) {
615         // Make sure that the next buffer output does not still
616         // depend on fragments from the last one decoded.
617         mNumFramesOutput = 0;
618         opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
619         mAnchorTimeUs = 0;
620         mSamplesToDiscard = mSeekPreRoll;
621         mHaveEOS = false;
622     }
623 }
624 
onReset()625 void SoftOpus::onReset() {
626     mInputBufferCount = 0;
627     mNumFramesOutput = 0;
628     if (mDecoder != NULL) {
629         opus_multistream_decoder_destroy(mDecoder);
630         mDecoder = NULL;
631     }
632     if (mHeader != NULL) {
633         delete mHeader;
634         mHeader = NULL;
635     }
636 
637     mOutputPortSettingsChange = NONE;
638     mHaveEOS = false;
639 }
640 
onPortEnableCompleted(OMX_U32 portIndex,bool enabled)641 void SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
642     if (portIndex != 1) {
643         return;
644     }
645 
646     switch (mOutputPortSettingsChange) {
647         case NONE:
648             break;
649 
650         case AWAITING_DISABLED:
651         {
652             CHECK(!enabled);
653             mOutputPortSettingsChange = AWAITING_ENABLED;
654             break;
655         }
656 
657         default:
658         {
659             CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
660             CHECK(enabled);
661             mOutputPortSettingsChange = NONE;
662             break;
663         }
664     }
665 }
666 
667 }  // namespace android
668 
669 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)670 android::SoftOMXComponent *createSoftOMXComponent(
671         const char *name, const OMX_CALLBACKTYPE *callbacks,
672         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
673     return new android::SoftOpus(name, callbacks, appData, component);
674 }
675