From fe834d30f4f3f51b754d55fecb36f11279733948 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Wed, 8 Jan 2014 14:49:08 -0800 Subject: [PATCH] Prepare for additional formats beyond 8-bit and 16-bit PCM This CL does the same thing for AudioTrack, that an earlier CL did for AudioRecord: > Change-Id: Ic3525f049e939bdf125d9f87ed39abd2690dcf9f Pull out the common parts of that earlier CL and move them to new header file android_media_AudioFormat.h. Use the new function audioFormatToNative() to convert from Java ENCODING_PCM_* to native AUDIO_FORMAT_*. Use audio_bytes_per_sample() instead of hard-coding the size of various formats. Use size_t for memory sizes. Change-Id: I7992dd6a2c9500126a6d7ae5fc1ed9f3312962d6 --- core/jni/android_media_AudioFormat.h | 38 +++++++++++++++++++++++ core/jni/android_media_AudioRecord.cpp | 18 +---------- core/jni/android_media_AudioTrack.cpp | 38 +++++++++++++++-------- media/java/android/media/AudioFormat.java | 3 +- 4 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 core/jni/android_media_AudioFormat.h diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h new file mode 100644 index 0000000000000..f4bab2629dac8 --- /dev/null +++ b/core/jni/android_media_AudioFormat.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ANDROID_MEDIA_AUDIOFORMAT_H +#define ANDROID_MEDIA_AUDIOFORMAT_H + +#include + +// keep these values in sync with AudioFormat.java +#define ENCODING_PCM_16BIT 2 +#define ENCODING_PCM_8BIT 3 + +static inline audio_format_t audioFormatToNative(int audioFormat) +{ + switch (audioFormat) { + case ENCODING_PCM_16BIT: + return AUDIO_FORMAT_PCM_16_BIT; + case ENCODING_PCM_8BIT: + return AUDIO_FORMAT_PCM_8_BIT; + default: + return AUDIO_FORMAT_INVALID; + } +} + +#endif // ANDROID_MEDIA_AUDIOFORMAT_H diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index aae20e0f1352a..353334d6b0fd7 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include "android_media_AudioFormat.h" // ---------------------------------------------------------------------------- @@ -49,10 +49,6 @@ struct audiorecord_callback_cookie { Condition cond; }; -// keep these values in sync with AudioFormat.java -#define ENCODING_PCM_16BIT 2 -#define ENCODING_PCM_8BIT 3 - static Mutex sLock; static SortedVector sAudioRecordCallBackCookies; @@ -81,18 +77,6 @@ jint android_media_translateRecorderErrorCode(int code) { } } -static audio_format_t audioFormatToNative(int audioFormat) -{ - switch (audioFormat) { - case ENCODING_PCM_16BIT: - return AUDIO_FORMAT_PCM_16_BIT; - case ENCODING_PCM_8BIT: - return AUDIO_FORMAT_PCM_8_BIT; - default: - return AUDIO_FORMAT_INVALID; - } -} - // ---------------------------------------------------------------------------- static void recorderCallback(int event, void* user, void *info) { diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index bc6dbb6fe40e3..2e419f17800c4 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include "android_media_AudioFormat.h" // ---------------------------------------------------------------------------- @@ -55,9 +55,6 @@ struct audiotrack_callback_cookie { // keep these values in sync with AudioTrack.java #define MODE_STATIC 0 #define MODE_STREAM 1 -// keep these values in sync with AudioFormat.java -#define ENCODING_PCM_16BIT 2 -#define ENCODING_PCM_8BIT 3 // ---------------------------------------------------------------------------- class AudioTrackJniStorage { @@ -244,7 +241,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // check the format. // This function was called from Java, so we compare the format against the Java constants - if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) { + audio_format_t format = audioFormatToNative(audioFormat); + if (format == AUDIO_FORMAT_INVALID) { ALOGE("Error creating AudioTrack: unsupported audio format."); return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT; @@ -253,20 +251,18 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled // in android_media_AudioTrack_native_write_byte() - if ((audioFormat == ENCODING_PCM_8BIT) + if ((format == AUDIO_FORMAT_PCM_8_BIT) && (memoryMode == MODE_STATIC)) { ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \ buff size of %dbytes, switching to 16bit, buff size of %dbytes", buffSizeInBytes, 2*buffSizeInBytes); - audioFormat = ENCODING_PCM_16BIT; + format = AUDIO_FORMAT_PCM_16_BIT; // we will need twice the memory to store the data buffSizeInBytes *= 2; } // compute the frame count - int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1; - audio_format_t format = audioFormat == ENCODING_PCM_16BIT ? - AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT; + const size_t bytesPerSample = audio_bytes_per_sample(format); int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample); jclass clazz = env->GetObjectClass(thiz); @@ -519,14 +515,26 @@ jint writeToTrack(const sp& track, jint audioFormat, jbyte* data, written = 0; } } else { - if (audioFormat == ENCODING_PCM_16BIT) { + const audio_format_t format = audioFormatToNative(audioFormat); + switch (format) { + + default: + // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT + // and AUDIO_FORMAT_PCM_8_BIT, due to the limited set of values for audioFormat. + // The next section of the switch will probably work for more formats, but it has only + // been tested for AUDIO_FORMAT_PCM_16_BIT, so that's why the "default" case fails. + break; + + case AUDIO_FORMAT_PCM_16_BIT: { // writing to shared memory, check for capacity if ((size_t)sizeInBytes > track->sharedBuffer()->size()) { sizeInBytes = track->sharedBuffer()->size(); } memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes); written = sizeInBytes; - } else if (audioFormat == ENCODING_PCM_8BIT) { + } break; + + case AUDIO_FORMAT_PCM_8_BIT: { // data contains 8bit data we need to expand to 16bit before copying // to the shared memory // writing to shared memory, check for capacity, @@ -543,6 +551,8 @@ jint writeToTrack(const sp& track, jint audioFormat, jbyte* data, // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide // the 8bit mixer restriction from the user of this function written = sizeInBytes; + } break; + } } return written; @@ -837,7 +847,9 @@ static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thi sampleRateInHertz, status); return -1; } - return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1); + const audio_format_t format = audioFormatToNative(audioFormat); + const size_t bytesPerSample = audio_bytes_per_sample(format); + return frameCount * nbChannels * bytesPerSample; } // ---------------------------------------------------------------------------- diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 49f498eaaa990..26e9cc53bcc65 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -31,7 +31,8 @@ public class AudioFormat { public static final int ENCODING_INVALID = 0; /** Default audio data format */ public static final int ENCODING_DEFAULT = 1; - // These two values must be kept in sync with JNI code for AudioTrack, AudioRecord + + // These two values must be kept in sync with core/jni/android_media_AudioFormat.h /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */ public static final int ENCODING_PCM_16BIT = 2; /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */