WebAudioMediaCodecBridge.java revision f2477e01787aa58f445919b809d89e252beef54f
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)package org.chromium.media;
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.content.Context;
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.media.AudioFormat;
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.media.MediaCodec;
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.media.MediaCodec.BufferInfo;
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.media.MediaExtractor;
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.media.MediaFormat;
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.os.ParcelFileDescriptor;
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.util.Log;
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import java.io.File;
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import java.nio.ByteBuffer;
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import org.chromium.base.CalledByNative;
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import org.chromium.base.JNINamespace;
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)@JNINamespace("media")
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class WebAudioMediaCodecBridge {
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    static final String LOG_TAG = "WebAudioMediaCodec";
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // TODO(rtoy): What is the correct timeout value for reading
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // from a file in memory?
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    static final long TIMEOUT_MICROSECONDS = 500;
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @CalledByNative
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    private static String CreateTempFile(Context ctx) throws java.io.IOException {
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        File outputDirectory = ctx.getCacheDir();
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        File outputFile = File.createTempFile("webaudio", ".dat", outputDirectory);
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return outputFile.getAbsolutePath();
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    @CalledByNative
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static boolean decodeAudioFile(Context ctx,
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                           long nativeMediaCodecBridge,
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           int inputFD,
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           long dataSize) {
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (dataSize < 0 || dataSize > 0x7fffffff)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return false;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        MediaExtractor extractor = new MediaExtractor();
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ParcelFileDescriptor encodedFD;
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        encodedFD = ParcelFileDescriptor.adoptFd(inputFD);
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        try {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            extractor.setDataSource(encodedFD.getFileDescriptor(), 0, dataSize);
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } catch (Exception e) {
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            e.printStackTrace();
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            encodedFD.detachFd();
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return false;
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (extractor.getTrackCount() <= 0) {
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            encodedFD.detachFd();
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            return false;
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        MediaFormat format = extractor.getTrackFormat(0);
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Number of channels specified in the file
64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        int inputChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // Number of channels the decoder will provide. (Not
67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // necessarily the same as inputChannelCount.  See
68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        // crbug.com/266006.)
69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        int outputChannelCount = inputChannelCount;
70ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        String mime = format.getString(MediaFormat.KEY_MIME);
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        long durationMicroseconds = 0;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (format.containsKey(MediaFormat.KEY_DURATION)) {
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            try {
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                durationMicroseconds = format.getLong(MediaFormat.KEY_DURATION);
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            } catch (Exception e) {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                Log.d(LOG_TAG, "Cannot get duration");
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            }
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        Log.d(LOG_TAG, "Initial: Tracks: " + extractor.getTrackCount() +
841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)              " Format: " + format);
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Create decoder
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        MediaCodec codec = MediaCodec.createDecoderByType(mime);
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        codec.start();
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // A track must be selected and will be used to read samples.
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extractor.selectTrack(0);
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        boolean sawInputEOS = false;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        boolean sawOutputEOS = false;
991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        boolean destinationInitialized = false;
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Keep processing until the output is done.
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        while (!sawOutputEOS) {
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (!sawInputEOS) {
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                // Input side
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECONDS);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                if (inputBufIndex >= 0) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    int sampleSize = extractor.readSampleData(dstBuf, 0);
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    long presentationTimeMicroSec = 0;
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    if (sampleSize < 0) {
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        sawInputEOS = true;
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        sampleSize = 0;
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    } else {
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        presentationTimeMicroSec = extractor.getSampleTime();
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    }
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    codec.queueInputBuffer(inputBufIndex,
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           0, /* offset */
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           sampleSize,
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           presentationTimeMicroSec,
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    if (!sawInputEOS) {
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        extractor.advance();
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    }
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                }
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            }
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Output side
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            MediaCodec.BufferInfo info = new BufferInfo();
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            final int outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_MICROSECONDS);
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (outputBufIndex >= 0) {
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                ByteBuffer buf = codecOutputBuffers[outputBufIndex];
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                if (!destinationInitialized) {
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    // Initialize the destination as late as possible to
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    // catch any changes in format. But be sure to
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    // initialize it BEFORE we send any decoded audio,
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    // and only initialize once.
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    Log.d(LOG_TAG, "Final:  Rate: " + sampleRate +
1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                          " Channels: " + inputChannelCount +
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                          " Mime: " + mime +
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                          " Duration: " + durationMicroseconds + " microsec");
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    nativeInitializeDestination(nativeMediaCodecBridge,
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                inputChannelCount,
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                sampleRate,
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                durationMicroseconds);
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    destinationInitialized = true;
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                }
1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                if (destinationInitialized && info.size > 0) {
156ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                    nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size,
157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                         inputChannelCount, outputChannelCount);
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                }
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                buf.clear();
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                codec.releaseOutputBuffer(outputBufIndex, false /* render */);
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    sawOutputEOS = true;
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                }
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                codecOutputBuffers = codec.getOutputBuffers();
168ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch            } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
169ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                MediaFormat newFormat = codec.getOutputFormat();
170ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                outputChannelCount = newFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                sampleRate = newFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
172ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                Log.d(LOG_TAG, "output format changed to " + newFormat);
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            }
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        encodedFD.detachFd();
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        codec.stop();
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        codec.release();
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        codec = null;
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return true;
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static native void nativeOnChunkDecoded(
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        long nativeWebAudioMediaCodecBridge, ByteBuffer buf, int size,
187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        int inputChannelCount, int outputChannelCount);
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static native void nativeInitializeDestination(
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        long nativeWebAudioMediaCodecBridge,
191ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        int inputChannelCount,
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int sampleRate,
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        long durationMicroseconds);
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
195