| /* |
| * Copyrightm (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License 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. |
| */ |
| |
| #include <string.h> |
| |
| #include "AudioCodec.h" |
| |
| namespace { |
| |
| int8_t gExponents[128] = { |
| 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, |
| 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| class UlawCodec : public AudioCodec |
| { |
| public: |
| int set(int sampleRate, const char *fmtp) { |
| mSampleCount = sampleRate / 50; |
| return mSampleCount; |
| } |
| int encode(void *payload, int16_t *samples); |
| int decode(int16_t *samples, void *payload, int length); |
| private: |
| int mSampleCount; |
| }; |
| |
| int UlawCodec::encode(void *payload, int16_t *samples) |
| { |
| int8_t *ulaws = (int8_t *)payload; |
| for (int i = 0; i < mSampleCount; ++i) { |
| int sample = samples[i]; |
| int sign = (sample >> 8) & 0x80; |
| if (sample < 0) { |
| sample = -sample; |
| } |
| sample += 132; |
| if (sample > 32767) { |
| sample = 32767; |
| } |
| int exponent = gExponents[sample >> 8]; |
| int mantissa = (sample >> (exponent + 3)) & 0x0F; |
| ulaws[i] = ~(sign | (exponent << 4) | mantissa); |
| } |
| return mSampleCount; |
| } |
| |
| int UlawCodec::decode(int16_t *samples, void *payload, int length) |
| { |
| int8_t *ulaws = (int8_t *)payload; |
| for (int i = 0; i < length; ++i) { |
| int ulaw = ~ulaws[i]; |
| int exponent = (ulaw >> 4) & 0x07; |
| int mantissa = ulaw & 0x0F; |
| int sample = (((mantissa << 3) + 132) << exponent) - 132; |
| samples[i] = (ulaw < 0 ? -sample : sample); |
| } |
| return length; |
| } |
| |
| AudioCodec *newUlawCodec() |
| { |
| return new UlawCodec; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| class AlawCodec : public AudioCodec |
| { |
| public: |
| int set(int sampleRate, const char *fmtp) { |
| mSampleCount = sampleRate / 50; |
| return mSampleCount; |
| } |
| int encode(void *payload, int16_t *samples); |
| int decode(int16_t *samples, void *payload, int length); |
| private: |
| int mSampleCount; |
| }; |
| |
| int AlawCodec::encode(void *payload, int16_t *samples) |
| { |
| int8_t *alaws = (int8_t *)payload; |
| for (int i = 0; i < mSampleCount; ++i) { |
| int sample = samples[i]; |
| int sign = (sample >> 8) & 0x80; |
| if (sample < 0) { |
| sample = -sample; |
| } |
| if (sample > 32767) { |
| sample = 32767; |
| } |
| int exponent = gExponents[sample >> 8]; |
| int mantissa = (sample >> (exponent == 0 ? 4 : exponent + 3)) & 0x0F; |
| alaws[i] = (sign | (exponent << 4) | mantissa) ^ 0xD5; |
| } |
| return mSampleCount; |
| } |
| |
| int AlawCodec::decode(int16_t *samples, void *payload, int length) |
| { |
| int8_t *alaws = (int8_t *)payload; |
| for (int i = 0; i < length; ++i) { |
| int alaw = alaws[i] ^ 0x55; |
| int exponent = (alaw >> 4) & 0x07; |
| int mantissa = alaw & 0x0F; |
| int sample = (exponent == 0 ? (mantissa << 4) + 8 : |
| ((mantissa << 3) + 132) << exponent); |
| samples[i] = (alaw < 0 ? sample : -sample); |
| } |
| return length; |
| } |
| |
| AudioCodec *newAlawCodec() |
| { |
| return new AlawCodec; |
| } |
| |
| struct AudioCodecType { |
| const char *name; |
| AudioCodec *(*create)(); |
| } gAudioCodecTypes[] = { |
| {"PCMA", newAlawCodec}, |
| {"PCMU", newUlawCodec}, |
| {NULL, NULL}, |
| }; |
| |
| } // namespace |
| |
| AudioCodec *newAudioCodec(const char *codecName) |
| { |
| AudioCodecType *type = gAudioCodecTypes; |
| while (type->name != NULL) { |
| if (strcasecmp(codecName, type->name) == 0) { |
| AudioCodec *codec = type->create(); |
| codec->name = type->name; |
| return codec; |
| } |
| ++type; |
| } |
| return NULL; |
| } |