diff options
Diffstat (limited to 'media')
22 files changed, 350 insertions, 157 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2978774..4d2e725 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -135,7 +135,7 @@ public class AudioManager { public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; /** The audio stream for system sounds */ public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; - /** The audio stream for the phone ring and message alerts */ + /** The audio stream for the phone ring */ public static final int STREAM_RING = AudioSystem.STREAM_RING; /** The audio stream for music playback */ public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; @@ -214,14 +214,13 @@ public class AudioManager { /** * Whether to include ringer modes as possible options when changing volume. * For example, if true and volume level is 0 and the volume is adjusted - * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent - * or vibrate mode. + * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or + * vibrate mode. * <p> - * By default this is on for stream types that are affected by the ringer - * mode (for example, the ring stream type). If this flag is included, this - * behavior will be present regardless of the stream type being affected by - * the ringer mode. - * + * By default this is on for the ring stream. If this flag is included, + * this behavior will be present regardless of the stream type being + * affected by the ringer mode. + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 1314ba1..fd990fe 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -339,7 +339,11 @@ public class AudioRecord * Releases the native AudioRecord resources. */ public void release() { - stop(); + try { + stop(); + } catch(IllegalStateException ise) { + // don't raise an exception, we're releasing the resources. + } native_release(); mState = STATE_UNINITIALIZED; } @@ -427,6 +431,56 @@ public class AudioRecord public int getPositionNotificationPeriod() { return native_get_pos_update_period(); } + + /** + * {@hide} + * Returns the minimum buffer size required for the successful creation of an AudioRecord + * object. + * @param sampleRateInHz the sample rate expressed in Hertz. + * @param channelConfig describes the configuration of the audio channels. + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and + * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} + * @param audioFormat the format in which the audio data is represented. + * See {@link AudioFormat#ENCODING_PCM_16BIT}. + * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the + * hardware, or an invalid parameter was passed, + * or {@link #ERROR} if the implementation was unable to query the hardware for its + * output properties, + * or the minimum buffer size expressed in of bytes. + */ + static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { + int channelCount = 0; + switch(channelConfig) { + case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT: + case AudioFormat.CHANNEL_CONFIGURATION_MONO: + channelCount = 1; + break; + case AudioFormat.CHANNEL_CONFIGURATION_STEREO: + channelCount = 2; + break; + case AudioFormat.CHANNEL_CONFIGURATION_INVALID: + default: + loge("getMinBufferSize(): Invalid channel configuration."); + return AudioRecord.ERROR_BAD_VALUE; + } + + // PCM_8BIT is not supported at the moment + if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) { + loge("getMinBufferSize(): Invalid audio format."); + return AudioRecord.ERROR_BAD_VALUE; + } + + int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); + if (size == 0) { + return AudioRecord.ERROR_BAD_VALUE; + } + else if (size == -1) { + return AudioRecord.ERROR; + } + else { + return size; + } + } //--------------------------------------------------------- @@ -699,6 +753,9 @@ public class AudioRecord private native final int native_set_pos_update_period(int updatePeriod); private native final int native_get_pos_update_period(); + + static private native final int native_get_min_buff_size( + int sampleRateInHz, int channelCount, int audioFormat); //--------------------------------------------------------- diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index f3d8957..bdabda7 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -349,9 +349,9 @@ public class AudioService extends IAudioService.Stub { // If either the client forces allowing ringer modes for this adjustment, // or the stream type is one that is affected by ringer modes if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 - || isStreamAffectedByRingerMode(streamType)) { + || streamType == AudioManager.STREAM_RING) { // Check if the ringer mode changes with this volume adjustment. If - // it does, it will handle adjusting the volome, so we won't below + // it does, it will handle adjusting the volume, so we won't below adjustVolume = checkForRingerModeChange(oldIndex, direction); } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 9bb1df9..74ffc1a 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -395,7 +395,11 @@ public class AudioTrack public void release() { // even though native_release() stops the native AudioTrack, we need to stop // AudioTrack subclasses too. - stop(); + try { + stop(); + } catch(IllegalStateException ise) { + // don't raise an exception, we're releasing the resources. + } native_release(); mState = STATE_UNINITIALIZED; } @@ -1007,4 +1011,4 @@ public class AudioTrack Log.e(TAG, "[ android.media.AudioTrack ] " + msg); } -}
\ No newline at end of file +} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 4a30114..3609826 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -19,6 +19,10 @@ package android.media; import android.view.Surface; import android.hardware.Camera; import java.io.IOException; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileDescriptor; +import android.util.Log; /** * Used to record audio and video. The recording control is based on a @@ -50,6 +54,7 @@ public class MediaRecorder static { System.loadLibrary("media_jni"); } + private final static String TAG = "MediaRecorder"; // The two fields below are accessed by native methods @SuppressWarnings("unused") @@ -57,7 +62,10 @@ public class MediaRecorder @SuppressWarnings("unused") private Surface mSurface; - + + private String mPath; + private FileDescriptor mFd; + /** * Default constructor. */ @@ -71,8 +79,6 @@ public class MediaRecorder * the camera object. Must call before prepare(). * * @param c the Camera to use for recording - * FIXME: Temporarily hidden until API approval - * @hide */ public native void setCamera(Camera c); @@ -104,7 +110,6 @@ public class MediaRecorder /** * Defines the video source. These constants are used with * {@link MediaRecorder#setVideoSource(int)}. - * @hide */ public final class VideoSource { /* Do not change these values without updating their counterparts @@ -152,7 +157,6 @@ public class MediaRecorder /** * Defines the video encoding. These constants are used with * {@link MediaRecorder#setVideoEncoder(int)}. - * @hide */ public final class VideoEncoder { /* Do not change these values without updating their counterparts @@ -187,7 +191,6 @@ public class MediaRecorder * @param video_source the video source to use * @throws IllegalStateException if it is called after setOutputFormat() * @see android.media.MediaRecorder.VideoSource - * @hide */ public native void setVideoSource(int video_source) throws IllegalStateException; @@ -214,7 +217,6 @@ public class MediaRecorder * @param height the height of the video to be captured * @throws IllegalStateException if it is called after * prepare() or before setOutputFormat() - * @hide */ public native void setVideoSize(int width, int height) throws IllegalStateException; @@ -227,7 +229,10 @@ public class MediaRecorder * @param rate the number of frames per second of video to capture * @throws IllegalStateException if it is called after * prepare() or before setOutputFormat(). - * @hide + * + * NOTE: On some devices that have auto-frame rate, this sets the + * maximum frame rate, not a constant frame rate. Actual frame rate + * will vary according to lighting conditions. */ public native void setVideoFrameRate(int rate) throws IllegalStateException; @@ -253,21 +258,43 @@ public class MediaRecorder * @throws IllegalStateException if it is called before * setOutputFormat() or after prepare() * @see android.media.MediaRecorder.VideoEncoder - * @hide */ public native void setVideoEncoder(int video_encoder) throws IllegalStateException; /** + * Pass in the file descriptor of the file to be written. Call this after + * setOutputFormat() but before prepare(). + * + * @param fd an open file descriptor to be written into. + * @throws IllegalStateException if it is called before + * setOutputFormat() or after prepare() + */ + public void setOutputFile(FileDescriptor fd) throws IllegalStateException + { + mPath = null; + mFd = fd; + } + + /** * Sets the path of the output file to be produced. Call this after * setOutputFormat() but before prepare(). * - * @param path The pathname to use() + * @param path The pathname to use. * @throws IllegalStateException if it is called before * setOutputFormat() or after prepare() */ - public native void setOutputFile(String path) throws IllegalStateException; + public void setOutputFile(String path) throws IllegalStateException + { + mFd = null; + mPath = path; + } + // native implementation + private native void _setOutputFile(FileDescriptor fd, long offset, long length) + throws IllegalStateException, IOException; + private native void _prepare() throws IllegalStateException, IOException; + /** * Prepares the recorder to begin capturing and encoding data. This method * must be called after setting up the desired audio and video sources, @@ -277,7 +304,18 @@ public class MediaRecorder * start() or before setOutputFormat(). * @throws IOException if prepare fails otherwise. */ - public native void prepare() throws IllegalStateException, IOException; + public void prepare() throws IllegalStateException, IOException + { + if (mPath != null) { + FileOutputStream f = new FileOutputStream(mPath); + _setOutputFile(f.getFD(), 0, 0); + } else if (mFd != null) { + _setOutputFile(mFd, 0, 0); + } else { + throw new IOException("No valid output file"); + } + _prepare(); + } /** * Begins capturing and encoding data to the file specified with diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 8eb638e..095749b 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -143,25 +143,17 @@ android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae) } static void -android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path) +android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { LOGV("setOutputFile"); - MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); - - if (path == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "Path is a NULL pointer"); - return; - } - const char *pathStr = env->GetStringUTFChars(path, NULL); - if (pathStr == NULL) { // Out of memory - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + if (fileDescriptor == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } - status_t opStatus = mr->setOutputFile(pathStr); - - // Make sure that local ref is released before a potential exception - env->ReleaseStringUTFChars(path, pathStr); - process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed."); + int fd = getParcelFileDescriptorFD(env, fileDescriptor); + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + status_t opStatus = mr->setOutputFile(fd, offset, length); + process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed."); } static void @@ -273,23 +265,23 @@ android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz) // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { - {"setCamera", "(Landroid/hardware/Camera;)V",(void *)android_media_MediaRecorder_setCamera}, - {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource}, - {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource}, - {"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat}, - {"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder}, - {"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder}, - {"setOutputFile", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setOutputFile}, - {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize}, - {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate}, - {"prepare", "()V", (void *)android_media_MediaRecorder_prepare}, - {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude}, - {"start", "()V", (void *)android_media_MediaRecorder_start}, - {"stop", "()V", (void *)android_media_MediaRecorder_stop}, - {"reset", "()V", (void *)android_media_MediaRecorder_reset}, - {"release", "()V", (void *)android_media_MediaRecorder_release}, - {"native_setup", "()V", (void *)android_media_MediaRecorder_native_setup}, - {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, + {"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera}, + {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource}, + {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource}, + {"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat}, + {"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder}, + {"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder}, + {"_setOutputFile", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaRecorder_setOutputFileFD}, + {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize}, + {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate}, + {"_prepare", "()V", (void *)android_media_MediaRecorder_prepare}, + {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude}, + {"start", "()V", (void *)android_media_MediaRecorder_start}, + {"stop", "()V", (void *)android_media_MediaRecorder_stop}, + {"reset", "()V", (void *)android_media_MediaRecorder_reset}, + {"release", "()V", (void *)android_media_MediaRecorder_release}, + {"native_setup", "()V", (void *)android_media_MediaRecorder_native_setup}, + {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, }; static const char* const kClassPathName = "android/media/MediaRecorder"; diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 559f9d5..02731825 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -491,10 +491,11 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV // initialize track int afFrameCount; int afSampleRate; - if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { + int streamType = mSoundPool->streamType(); + if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { afFrameCount = kDefaultFrameCount; } - if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { afSampleRate = kDefaultSampleRate; } int numChannels = sample->numChannels(); @@ -522,10 +523,10 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV void *userData = (void *)((unsigned long)this | toggle); #ifdef USE_SHARED_MEM_BUFFER - newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(), + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), numChannels, sample->getIMemory(), 0, callback, userData); #else - newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(), + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), numChannels, frameCount, 0, callback, userData, bufferFrames); #endif if (newTrack->initCheck() != NO_ERROR) { diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a987b92..3d39181 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -128,22 +128,8 @@ status_t AudioRecord::set( return BAD_VALUE; } - size_t inputBuffSizeInBytes = -1; - if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes) - != NO_ERROR) { - LOGE("AudioSystem could not query the input buffer size."); - return NO_INIT; - } - if (inputBuffSizeInBytes == 0) { - LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d", - sampleRate, channelCount, format); - return BAD_VALUE; - } - int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); - - // We use 2* size of input buffer for ping pong use of record buffer. - int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes; - LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); + // TODO: Get input frame count from hardware. + int minFrameCount = 1024*2; if (frameCount == 0) { frameCount = minFrameCount; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index cf91105..63dfc3b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -20,7 +20,6 @@ #include <utils/Log.h> #include <utils/IServiceManager.h> #include <media/AudioSystem.h> -#include <media/AudioTrack.h> #include <math.h> namespace android { @@ -31,9 +30,10 @@ sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; // Cached values -int AudioSystem::gOutSamplingRate = 0; -int AudioSystem::gOutFrameCount = 0; -uint32_t AudioSystem::gOutLatency = 0; +int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES]; +int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES]; +uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES]; +bool AudioSystem::gA2dpEnabled; // Cached values for recording queries uint32_t AudioSystem::gPrevInSamplingRate = 16000; int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT; @@ -66,9 +66,12 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() gAudioFlinger = interface_cast<IAudioFlinger>(binder); gAudioFlinger->registerClient(gAudioFlingerClient); // Cache frequently accessed parameters - gOutFrameCount = (int)gAudioFlinger->frameCount(); - gOutSamplingRate = (int)gAudioFlinger->sampleRate(); - gOutLatency = gAudioFlinger->latency(); + for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) { + gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output); + gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output); + gOutLatency[output] = gAudioFlinger->latency(output); + } + gA2dpEnabled = gAudioFlinger->isA2dpEnabled(); } LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?"); return gAudioFlinger; @@ -147,7 +150,7 @@ status_t AudioSystem::getMasterMute(bool* mute) status_t AudioSystem::setStreamVolume(int stream, float value) { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; af->setStreamVolume(stream, value); @@ -156,7 +159,7 @@ status_t AudioSystem::setStreamVolume(int stream, float value) status_t AudioSystem::setStreamMute(int stream, bool mute) { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; af->setStreamMute(stream, mute); @@ -165,7 +168,7 @@ status_t AudioSystem::setStreamMute(int stream, bool mute) status_t AudioSystem::getStreamVolume(int stream, float* volume) { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; *volume = af->streamVolume(stream); @@ -174,7 +177,7 @@ status_t AudioSystem::getStreamVolume(int stream, float* volume) status_t AudioSystem::getStreamMute(int stream, bool* mute) { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; *mute = af->streamMute(stream); @@ -252,37 +255,48 @@ int AudioSystem::logToLinear(float volume) return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; } -status_t AudioSystem::getOutputSamplingRate(int* samplingRate) +status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) { - if (gOutSamplingRate == 0) { + int output = getOutput(streamType); + + if (gOutSamplingRate[output] == 0) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; // gOutSamplingRate is updated by get_audio_flinger() } - *samplingRate = gOutSamplingRate; + LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]); + *samplingRate = gOutSamplingRate[output]; return NO_ERROR; } -status_t AudioSystem::getOutputFrameCount(int* frameCount) +status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) { - if (gOutFrameCount == 0) { + int output = getOutput(streamType); + + if (gOutFrameCount[output] == 0) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; // gOutFrameCount is updated by get_audio_flinger() } - *frameCount = gOutFrameCount; + LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]); + + *frameCount = gOutFrameCount[output]; return NO_ERROR; } -status_t AudioSystem::getOutputLatency(uint32_t* latency) +status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) { - if (gOutLatency == 0) { + int output = getOutput(streamType); + + if (gOutLatency[output] == 0) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; // gOutLatency is updated by get_audio_flinger() - } - *latency = gOutLatency; + } + LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]); + + *latency = gOutLatency[output]; return NO_ERROR; } @@ -315,24 +329,23 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int ch void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); - AudioSystem::gOutSamplingRate = 0; - AudioSystem::gOutFrameCount = 0; - AudioSystem::gOutLatency = 0; + + for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) { + gOutFrameCount[output] = 0; + gOutSamplingRate[output] = 0; + gOutLatency[output] = 0; + } AudioSystem::gInBuffSize = 0; - + if (gAudioErrorCallback) { gAudioErrorCallback(DEAD_OBJECT); } LOGW("AudioFlinger server died!"); } -void AudioSystem::AudioFlingerClient::audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) { - - AudioSystem::gOutFrameCount = frameCount; - AudioSystem::gOutSamplingRate = samplingRate; - AudioSystem::gOutLatency = latency; - - LOGV("AudioFlinger output changed!"); +void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) { + gA2dpEnabled = enabled; + LOGV("AudioFlinger A2DP enabled status changed! %d", enabled); } void AudioSystem::setErrorCallback(audio_error_callback cb) { @@ -340,5 +353,31 @@ void AudioSystem::setErrorCallback(audio_error_callback cb) { gAudioErrorCallback = cb; } +int AudioSystem::getOutput(int streamType) +{ + if (streamType == DEFAULT) { + streamType = MUSIC; + } + if (gA2dpEnabled && routedToA2dpOutput(streamType)) { + return AUDIO_OUTPUT_A2DP; + } else { + return AUDIO_OUTPUT_HARDWARE; + } +} + +bool AudioSystem::routedToA2dpOutput(int streamType) { + switch(streamType) { + case MUSIC: + case VOICE_CALL: + case BLUETOOTH_SCO: + case SYSTEM: + return true; + default: + return false; + } +} + + + }; // namespace android diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 63b2012..1ffad46 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -128,22 +128,21 @@ status_t AudioTrack::set( return NO_INIT; } int afSampleRate; - if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { return NO_INIT; } int afFrameCount; - if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { + if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { return NO_INIT; } uint32_t afLatency; - if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) { + if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { return NO_INIT; } - // handle default values first. - if (streamType == DEFAULT) { - streamType = MUSIC; + if (streamType == AudioSystem::DEFAULT) { + streamType = AudioSystem::MUSIC; } if (sampleRate == 0) { sampleRate = afSampleRate; @@ -260,7 +259,7 @@ status_t AudioTrack::set( mMarkerPosition = 0; mNewPosition = 0; mUpdatePeriod = 0; - + return NO_ERROR; } @@ -434,7 +433,7 @@ void AudioTrack::setSampleRate(int rate) { int afSamplingRate; - if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) { return; } // Resampler implementation limits input sampling rate to 2 x output sampling rate. diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 4215820..5cbb25c 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -53,7 +53,8 @@ enum { SET_PARAMETER, REGISTER_CLIENT, GET_INPUTBUFFERSIZE, - WAKE_UP + WAKE_UP, + IS_A2DP_ENABLED }; class BpAudioFlinger : public BpInterface<IAudioFlinger> @@ -123,42 +124,47 @@ public: return interface_cast<IAudioRecord>(reply.readStrongBinder()); } - virtual uint32_t sampleRate() const + virtual uint32_t sampleRate(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(output); remote()->transact(SAMPLE_RATE, data, &reply); return reply.readInt32(); } - virtual int channelCount() const + virtual int channelCount(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(output); remote()->transact(CHANNEL_COUNT, data, &reply); return reply.readInt32(); } - virtual int format() const + virtual int format(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(output); remote()->transact(FORMAT, data, &reply); return reply.readInt32(); } - virtual size_t frameCount() const + virtual size_t frameCount(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(output); remote()->transact(FRAME_COUNT, data, &reply); return reply.readInt32(); } - virtual uint32_t latency() const + virtual uint32_t latency(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(output); remote()->transact(LATENCY, data, &reply); return reply.readInt32(); } @@ -333,6 +339,14 @@ public: remote()->transact(WAKE_UP, data, &reply); return; } + + virtual bool isA2dpEnabled() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(IS_A2DP_ENABLED, data, &reply); + return (bool)reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -385,27 +399,32 @@ status_t BnAudioFlinger::onTransact( } break; case SAMPLE_RATE: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( sampleRate() ); + int output = data.readInt32(); + reply->writeInt32( sampleRate(output) ); return NO_ERROR; } break; case CHANNEL_COUNT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( channelCount() ); + int output = data.readInt32(); + reply->writeInt32( channelCount(output) ); return NO_ERROR; } break; case FORMAT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( format() ); + int output = data.readInt32(); + reply->writeInt32( format(output) ); return NO_ERROR; } break; case FRAME_COUNT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( frameCount() ); + int output = data.readInt32(); + reply->writeInt32( frameCount(output) ); return NO_ERROR; } break; case LATENCY: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32( latency() ); + int output = data.readInt32(); + reply->writeInt32( latency(output) ); return NO_ERROR; } break; case SET_MASTER_VOLUME: { @@ -519,7 +538,11 @@ status_t BnAudioFlinger::onTransact( wakeUp(); return NO_ERROR; } break; - + case IS_A2DP_ENABLED: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( (int)isA2dpEnabled() ); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp index d956266..5feb11f 100644 --- a/media/libmedia/IAudioFlingerClient.cpp +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -38,13 +38,11 @@ public: { } - void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) + void a2dpEnabledChanged(bool enabled) { Parcel data, reply; data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); - data.writeInt32(frameCount); - data.writeInt32(samplingRate); - data.writeInt32(latency); + data.writeInt32((int)enabled); remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply); } }; @@ -65,10 +63,8 @@ status_t BnAudioFlingerClient::onTransact( switch(code) { case AUDIO_OUTPUT_CHANGED: { CHECK_INTERFACE(IAudioFlingerClient, data, reply); - uint32_t frameCount = data.readInt32(); - uint32_t samplingRate = data.readInt32(); - uint32_t latency = data.readInt32(); - audioOutputChanged(frameCount, samplingRate, latency); + bool enabled = (bool)data.readInt32(); + a2dpEnabledChanged(enabled); return NO_ERROR; } break; default: diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index 1f6d599..507d03e 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -39,7 +39,8 @@ enum { SET_OUTPUT_FORMAT, SET_VIDEO_ENCODER, SET_AUDIO_ENCODER, - SET_OUTPUT_FILE, + SET_OUTPUT_FILE_PATH, + SET_OUTPUT_FILE_FD, SET_VIDEO_SIZE, SET_VIDEO_FRAMERATE, SET_PREVIEW_SURFACE, @@ -139,7 +140,18 @@ public: Parcel data, reply; data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); data.writeCString(path); - remote()->transact(SET_OUTPUT_FILE, data, &reply); + remote()->transact(SET_OUTPUT_FILE_PATH, data, &reply); + return reply.readInt32(); + } + + status_t setOutputFile(int fd, int64_t offset, int64_t length) { + LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length); + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor()); + data.writeFileDescriptor(fd); + data.writeInt64(offset); + data.writeInt64(length); + remote()->transact(SET_OUTPUT_FILE_FD, data, &reply); return reply.readInt32(); } @@ -330,13 +342,22 @@ status_t BnMediaRecorder::onTransact( return NO_ERROR; } break; - case SET_OUTPUT_FILE: { - LOGV("SET_OUTPUT_FILE"); + case SET_OUTPUT_FILE_PATH: { + LOGV("SET_OUTPUT_FILE_PATH"); CHECK_INTERFACE(IMediaRecorder, data, reply); const char* path = data.readCString(); reply->writeInt32(setOutputFile(path)); return NO_ERROR; } break; + case SET_OUTPUT_FILE_FD: { + LOGV("SET_OUTPUT_FILE_FD"); + CHECK_INTERFACE(IMediaRecorder, data, reply); + int fd = dup(data.readFileDescriptor()); + int64_t offset = data.readInt64(); + int64_t length = data.readInt64(); + reply->writeInt32(setOutputFile(fd, offset, length)); + return NO_ERROR; + } break; case SET_VIDEO_SIZE: { LOGV("SET_VIDEO_SIZE"); CHECK_INTERFACE(IMediaRecorder, data, reply); diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index ead24d4..9bd75c2 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -96,7 +96,7 @@ int JetPlayer::init() // create the output AudioTrack mAudioTrack = new AudioTrack(); - mAudioTrack->set(AudioTrack::MUSIC, //TODO parametrize this + mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this pLibConfig->sampleRate, 1, // format = PCM 16bits per sample, pLibConfig->numChannels, diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index fa36460..7fafc56 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -93,7 +93,7 @@ ToneGenerator::ToneGenerator(int streamType, float volume) { mState = TONE_IDLE; - if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) { LOGE("Unable to marshal AudioFlinger"); return; } @@ -182,7 +182,7 @@ bool ToneGenerator::startTone(int toneType) { mLock.lock(); if (mState == TONE_STARTING) { if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) { - LOGE("--- timed out"); + LOGE("--- Immediate start timed out"); mState = TONE_IDLE; } } @@ -200,7 +200,7 @@ bool ToneGenerator::startTone(int toneType) { } LOGV("cond received"); } else { - LOGE("--- timed out"); + LOGE("--- Delayed start timed out"); mState = TONE_IDLE; } } @@ -235,7 +235,7 @@ void ToneGenerator::stopTone() { if (lStatus == NO_ERROR) { LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000)); } else { - LOGE("--- timed out"); + LOGE("--- Stop timed out"); mState = TONE_IDLE; mpAudioTrack->stop(); } diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 31ff507..bd8579c 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -82,7 +82,7 @@ MediaPlayer::MediaPlayer() mListener = NULL; mCookie = NULL; mDuration = -1; - mStreamType = AudioTrack::MUSIC; + mStreamType = AudioSystem::MUSIC; mCurrentPosition = -1; mSeekPosition = -1; mCurrentState = MEDIA_PLAYER_IDLE; diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index 6ee4c0d..4ab26ac 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -248,7 +248,33 @@ status_t MediaRecorder::setOutputFile(const char* path) status_t ret = mMediaRecorder->setOutputFile(path); if (OK != ret) { - LOGV("setAudioEncoder failed: %d", ret); + LOGV("setOutputFile failed: %d", ret); + mCurrentState = MEDIA_RECORDER_ERROR; + return UNKNOWN_ERROR; + } + mIsOutputFileSet = true; + return ret; +} + +status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length) +{ + LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length); + if(mMediaRecorder == NULL) { + LOGE("media recorder is not initialized yet"); + return INVALID_OPERATION; + } + if (mIsOutputFileSet) { + LOGE("output file has already been set"); + return INVALID_OPERATION; + } + if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) { + LOGE("setOutputFile called in an invalid state(%d)", mCurrentState); + return INVALID_OPERATION; + } + + status_t ret = mMediaRecorder->setOutputFile(fd, offset, length); + if (OK != ret) { + LOGV("setOutputFile failed: %d", ret); mCurrentState = MEDIA_RECORDER_ERROR; return UNKNOWN_ERROR; } @@ -306,7 +332,7 @@ status_t MediaRecorder::prepare() return INVALID_OPERATION; } if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) { - LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState); + LOGE("prepare called in an invalid state: %d", mCurrentState); return INVALID_OPERATION; } @@ -328,7 +354,7 @@ status_t MediaRecorder::getMaxAmplitude(int* max) return INVALID_OPERATION; } if (mCurrentState & MEDIA_RECORDER_ERROR) { - LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState); + LOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState); return INVALID_OPERATION; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9e366e2..97e3536 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -818,7 +818,7 @@ Exit: MediaPlayerService::AudioOutput::AudioOutput() { mTrack = 0; - mStreamType = AudioTrack::MUSIC; + mStreamType = AudioSystem::MUSIC; mLeftVolume = 1.0; mRightVolume = 1.0; mLatency = 0; @@ -900,15 +900,15 @@ status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelC int afFrameCount; int frameCount; - if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { + if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) { return NO_INIT; } - if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) { + if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) { return NO_INIT; } - frameCount = (sampleRate*afFrameCount)/afSampleRate; - AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount*bufferCount); + frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate; + AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount); if ((t == 0) || (t->initCheck() != NO_ERROR)) { LOGE("Unable to create audio track"); delete t; diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index f326a0e..e8ba17f 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -121,6 +121,17 @@ status_t MediaRecorderClient::setOutputFile(const char* path) return mRecorder->setOutputFile(path); } +status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length) +{ + LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length); + Mutex::Autolock lock(mLock); + if (mRecorder == NULL) { + LOGE("recorder is not initialized"); + return NO_INIT; + } + return mRecorder->setOutputFile(fd, offset, length); +} + status_t MediaRecorderClient::setVideoSize(int width, int height) { LOGV("setVideoSize(%dx%d)", width, height); diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h index 3158017..2b80c10 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.h +++ b/media/libmediaplayerservice/MediaRecorderClient.h @@ -36,6 +36,7 @@ public: virtual status_t setVideoEncoder(int ve); virtual status_t setAudioEncoder(int ae); virtual status_t setOutputFile(const char* path); + virtual status_t setOutputFile(int fd, int64_t offset, int64_t length); virtual status_t setVideoSize(int width, int height); virtual status_t setVideoFrameRate(int frames_per_second); virtual status_t prepare(); diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index 7ce2fab..d03caa5 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -58,7 +58,7 @@ static const S_EAS_LIB_CONFIG* pLibConfig = NULL; MidiFile::MidiFile() : mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR), - mStreamType(AudioTrack::MUSIC), mLoop(false), mExit(false), + mStreamType(AudioSystem::MUSIC), mLoop(false), mExit(false), mPaused(false), mRender(false), mTid(-1) { LOGV("constructor"); diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp index 009d628..0ad335f 100644 --- a/media/libmediaplayerservice/VorbisPlayer.cpp +++ b/media/libmediaplayerservice/VorbisPlayer.cpp @@ -55,7 +55,7 @@ static status_t STATE_OPEN = 2; VorbisPlayer::VorbisPlayer() : mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR), - mStreamType(AudioTrack::MUSIC), mLoop(false), mAndroidLoop(false), + mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false), mExit(false), mPaused(false), mRender(false), mRenderTid(-1) { LOGV("constructor\n"); |
