/* * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.amazonaws.mobileconnectors.lex.interactionkit.internal.audio.encoder; import com.google.common.base.Preconditions; import com.google.common.net.MediaType; import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.List; /** * A buffering audio encoder that buffers audio and only encodes full frames of * audio. */ public class BufferedAudioEncoder implements AudioEncoder { private final AudioEncoder mEncoder; private final ShortBuffer mSamplesBuffer; /** * Create a BufferedAudioEncoder that wraps an underlying AudioEncoder. * * @param encoder the underlying audio encoder. */ public BufferedAudioEncoder(final AudioEncoder encoder) { Preconditions.checkNotNull(encoder, "AudioEncoder cannot be null"); mEncoder = encoder; mSamplesBuffer = ShortBuffer.wrap(new short[mEncoder.getFrameSize()]); } @Override public byte[] encode(final short[] samples, final int numSamples) throws AudioEncoderException { Preconditions.checkArgument(samples.length >= numSamples, "Number of samples cannot exceed buffer size"); int samplesProcessed = 0; int toWrite = 0; final List<byte[]> encodedBytesList = new ArrayList<byte[]>(); final short[] buffer = new short[mSamplesBuffer.capacity()]; // Loop while there are enough samples to fill the buffer. while (mSamplesBuffer.remaining() <= numSamples - samplesProcessed) { // Copy samples into buffer. toWrite = mSamplesBuffer.remaining(); System.arraycopy(samples, samplesProcessed, buffer, 0, toWrite); mSamplesBuffer.put(buffer, 0, toWrite); samplesProcessed += toWrite; // Process samples. encodedBytesList .add(mEncoder.encode(mSamplesBuffer.array(), mSamplesBuffer.capacity())); mSamplesBuffer.clear(); } // If any samples remain, copy into buffer. mSamplesBuffer.put(samples, samplesProcessed, numSamples - samplesProcessed); return concatenateBytes(encodedBytesList); } /** * Concatenate a list of byte arrays into one array. * * @param byteList the list of byte arrays. * @return the concatenated byte array. */ private byte[] concatenateBytes(final List<byte[]> byteList) { int size = 0; for (final byte[] byteArray : byteList) { size += byteArray.length; } final byte[] concatenatedByteArray = new byte[size]; int offset = 0; for (final byte[] byteArray : byteList) { System.arraycopy(byteArray, 0, concatenatedByteArray, offset, byteArray.length); offset += byteArray.length; } return concatenatedByteArray; } @Override public MediaType getMediaType() { return mEncoder.getMediaType(); } @Override public int getFrameSize() { return mEncoder.getFrameSize(); } @Override public int getPacketSize() { return mEncoder.getPacketSize(); } @Override public void close() { mEncoder.close(); } /** * Make a copy of the encoder. * * @return a copy of the encoder. */ @Override public final BufferedAudioEncoder newEncoder() { return new BufferedAudioEncoder(mEncoder.newEncoder()); } }