summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/Android.mk1
-rw-r--r--media/libmedia/AudioRecord.cpp25
-rw-r--r--media/libmedia/AudioSystem.cpp144
-rw-r--r--media/libmedia/AudioTrack.cpp62
-rw-r--r--media/libmedia/IAudioFlinger.cpp93
-rw-r--r--media/libmedia/IAudioFlingerClient.cpp77
-rw-r--r--media/libmedia/IMediaRecorder.cpp68
-rw-r--r--media/libmedia/JetPlayer.cpp81
-rw-r--r--media/libmedia/ToneGenerator.cpp43
-rw-r--r--media/libmedia/mediaplayer.cpp25
-rw-r--r--media/libmedia/mediarecorder.cpp162
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp267
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp32
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h3
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp22
-rw-r--r--media/libmediaplayerservice/MidiFile.h2
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.cpp6
17 files changed, 833 insertions, 280 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2a697b9..8020da2 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioTrack.cpp \
IAudioFlinger.cpp \
+ IAudioFlingerClient.cpp \
IAudioTrack.cpp \
IAudioRecord.cpp \
AudioRecord.cpp \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index e833c85..7594ff0 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,8 +128,23 @@ status_t AudioRecord::set(
return BAD_VALUE;
}
- // TODO: Get input frame count from hardware.
- int minFrameCount = 1024*2;
+ // validate framecount
+ 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);
if (frameCount == 0) {
frameCount = minFrameCount;
@@ -144,7 +159,11 @@ status_t AudioRecord::set(
// open record channel
status_t status;
sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
- sampleRate, format, channelCount, frameCount, flags, &status);
+ sampleRate, format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ &status);
if (record == 0) {
LOGE("AudioFlinger could not create record track, status: %d", status);
return status;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a375b55..63dfc3b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -15,10 +15,11 @@
*/
#define LOG_TAG "AudioSystem"
+//#define LOG_NDEBUG 0
+
#include <utils/Log.h>
#include <utils/IServiceManager.h>
#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
#include <math.h>
namespace android {
@@ -26,12 +27,18 @@ namespace android {
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
-sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier;
+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;
+int AudioSystem::gPrevInChannelCount = 1;
+size_t AudioSystem::gInBuffSize = 0;
// establish binder interface to AudioFlinger service
@@ -48,19 +55,23 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
LOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
- if (gDeathNotifier == NULL) {
- gDeathNotifier = new DeathNotifier();
+ if (gAudioFlingerClient == NULL) {
+ gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
- binder->linkToDeath(gDeathNotifier);
+ binder->linkToDeath(gAudioFlingerClient);
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;
@@ -139,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);
@@ -148,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);
@@ -157,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);
@@ -166,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);
@@ -244,60 +255,129 @@ 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;
- // gOutSamplingRate is updated by get_audio_flinger()
+ // 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;
+}
+
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+ size_t* buffSize)
+{
+ // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
+ if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
+ || (channelCount != gPrevInChannelCount)) {
+ // save the request params
+ gPrevInSamplingRate = sampleRate;
+ gPrevInFormat = format;
+ gPrevInChannelCount = channelCount;
+
+ gInBuffSize = 0;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+ gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
+ }
+ *buffSize = gInBuffSize;
return NO_ERROR;
}
// ---------------------------------------------------------------------------
-void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) {
+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::a2dpEnabledChanged(bool enabled) {
+ gA2dpEnabled = enabled;
+ LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
+}
+
void AudioSystem::setErrorCallback(audio_error_callback cb) {
Mutex::Autolock _l(AudioSystem::gLock);
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 f9f8568..d26b0c5 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;
@@ -157,7 +156,7 @@ status_t AudioTrack::set(
}
// validate parameters
- if (((format != AudioSystem::PCM_8_BIT) || mSharedBuffer != 0) &&
+ if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
(format != AudioSystem::PCM_16_BIT)) {
LOGE("Invalid format");
return BAD_VALUE;
@@ -169,6 +168,8 @@ status_t AudioTrack::set(
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+ if (minBufCount < 2) minBufCount = 2;
+
// When playing from shared buffer, playback will start even if last audioflinger
// block is partly filled.
if (sharedBuffer != 0 && minBufCount > 1) {
@@ -260,7 +261,7 @@ status_t AudioTrack::set(
mMarkerPosition = 0;
mNewPosition = 0;
mUpdatePeriod = 0;
-
+
return NO_ERROR;
}
@@ -317,7 +318,7 @@ void AudioTrack::start()
{
sp<AudioTrackThread> t = mAudioTrackThread;
- LOGV("start");
+ LOGV("start %p", this);
if (t != 0) {
if (t->exitPending()) {
if (t->requestExitAndWait() == WOULD_BLOCK) {
@@ -349,7 +350,7 @@ void AudioTrack::stop()
{
sp<AudioTrackThread> t = mAudioTrackThread;
- LOGV("stop");
+ LOGV("stop %p", this);
if (t != 0) {
t->mLock.lock();
}
@@ -434,12 +435,12 @@ 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.
+ if (rate <= 0) rate = 1;
if (rate > afSamplingRate*2) rate = afSamplingRate*2;
-
if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
mCblk->sampleRate = rate;
@@ -467,10 +468,15 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
if (loopStart >= loopEnd ||
loopEnd - loopStart > mFrameCount) {
- LOGW("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+ LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
return BAD_VALUE;
}
- // TODO handle shared buffer here: limit loop end to framecount
+
+ if ((mSharedBuffer != 0) && (loopEnd > mFrameCount)) {
+ LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
+ loopStart, loopEnd, mFrameCount);
+ return BAD_VALUE;
+ }
cblk->loopStart = loopStart;
cblk->loopEnd = loopEnd;
@@ -603,13 +609,20 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += WAIT_PERIOD_MS;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
- LOGW( "obtainBuffer timed out (is the CPU pegged?) "
- "user=%08x, server=%08x", cblk->user, cblk->server);
- mAudioTrack->start(); // FIXME: Wake up audioflinger
- timeout = 1;
+ // timing out when a loop has been set and we have already written upto loop end
+ // is a normal condition: no need to wake AudioFlinger up.
+ if (cblk->user < cblk->loopEnd) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
+ "user=%08x, server=%08x", this, cblk->user, cblk->server);
+ //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
+ cblk->lock.unlock();
+ mAudioTrack->start();
+ cblk->lock.lock();
+ timeout = 1;
+ }
cblk->waitTimeMs = 0;
}
- ;
+
if (--waitCount == 0) {
return TIMED_OUT;
}
@@ -668,7 +681,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
return BAD_VALUE;
}
- LOGV("write %d bytes, mActive=%d", userSize, mActive);
+ LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
ssize_t written = 0;
const int8_t *src = (const int8_t *)buffer;
@@ -795,7 +808,14 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
writtenSize = audioBuffer.size;
// Sanity check on returned size
- if (ssize_t(writtenSize) <= 0) break;
+ if (ssize_t(writtenSize) <= 0) {
+ // The callback is done filling buffers
+ // Keep this thread going to handle timed events and
+ // still try to get more data in intervals of WAIT_PERIOD_MS
+ // but don't just loop and block the CPU, so wait
+ usleep(WAIT_PERIOD_MS*1000);
+ break;
+ }
if (writtenSize > reqSize) writtenSize = reqSize;
if (mFormat == AudioSystem::PCM_8_BIT) {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 018ea6c..5cbb25c 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -51,6 +51,10 @@ enum {
GET_MIC_MUTE,
IS_MUSIC_ACTIVE,
SET_PARAMETER,
+ REGISTER_CLIENT,
+ GET_INPUTBUFFERSIZE,
+ WAKE_UP,
+ IS_A2DP_ENABLED
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -120,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();
}
@@ -303,6 +312,41 @@ public:
remote()->transact(SET_PARAMETER, data, &reply);
return reply.readInt32();
}
+
+ virtual void registerClient(const sp<IAudioFlingerClient>& client)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeStrongBinder(client->asBinder());
+ remote()->transact(REGISTER_CLIENT, data, &reply);
+ }
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void wakeUp()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ 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");
@@ -355,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: {
@@ -470,6 +519,30 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( setParameter(key, value) );
return NO_ERROR;
} break;
+ case REGISTER_CLIENT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
+ registerClient(client);
+ return NO_ERROR;
+ } break;
+ case GET_INPUTBUFFERSIZE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
+ return NO_ERROR;
+ } break;
+ case WAKE_UP: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ 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
new file mode 100644
index 0000000..5feb11f
--- /dev/null
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "IAudioFlingerClient"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlingerClient.h>
+
+namespace android {
+
+enum {
+ AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
+{
+public:
+ BpAudioFlingerClient(const sp<IBinder>& impl)
+ : BpInterface<IAudioFlingerClient>(impl)
+ {
+ }
+
+ void a2dpEnabledChanged(bool enabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
+ data.writeInt32((int)enabled);
+ remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnAudioFlingerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case AUDIO_OUTPUT_CHANGED: {
+ CHECK_INTERFACE(IAudioFlingerClient, data, reply);
+ bool enabled = (bool)data.readInt32();
+ a2dpEnabledChanged(enabled);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 1f6d599..84d08c4 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -21,6 +21,7 @@
#include <utils/Parcel.h>
#include <ui/ISurface.h>
#include <ui/ICamera.h>
+#include <media/IMediaPlayerClient.h>
#include <media/IMediaRecorder.h>
namespace android {
@@ -39,11 +40,14 @@ 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_PARAMETERS,
SET_PREVIEW_SURFACE,
- SET_CAMERA
+ SET_CAMERA,
+ SET_LISTENER
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -139,7 +143,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();
}
@@ -164,6 +179,26 @@ public:
return reply.readInt32();
}
+ status_t setParameters(const String8& params)
+ {
+ LOGV("setParameter(%s)", params.string());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeString8(params);
+ remote()->transact(SET_PARAMETERS, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setListener(const sp<IMediaPlayerClient>& listener)
+ {
+ LOGV("setListener(%p)", listener.get());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+ remote()->transact(SET_LISTENER, data, &reply);
+ return reply.readInt32();
+ }
+
status_t prepare()
{
LOGV("prepare");
@@ -330,13 +365,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);
@@ -352,6 +396,20 @@ status_t BnMediaRecorder::onTransact(
reply->writeInt32(setVideoFrameRate(frames_per_second));
return NO_ERROR;
} break;
+ case SET_PARAMETERS: {
+ LOGV("SET_PARAMETER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(setParameters(data.readString8()));
+ return NO_ERROR;
+ } break;
+ case SET_LISTENER: {
+ LOGV("SET_LISTENER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ sp<IMediaPlayerClient> listener =
+ interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ reply->writeInt32(setListener(listener));
+ return NO_ERROR;
+ } break;
case SET_PREVIEW_SURFACE: {
LOGV("SET_PREVIEW_SURFACE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index f0edf88..2c62104 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -86,8 +86,8 @@ int JetPlayer::init()
mState = EAS_STATE_ERROR;
return result;
}
- // init the JET library
- result = JET_Init(mEasData, NULL, 0);
+ // init the JET library with the default app event controller range
+ result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
if( result != EAS_SUCCESS) {
LOGE("JetPlayer::init(): Error initializing JET library, aborting.");
mState = EAS_STATE_ERROR;
@@ -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,
@@ -200,6 +200,11 @@ int JetPlayer::render() {
while (!mRender)
{
LOGV("JetPlayer::render(): signal wait");
+ if (audioStarted) {
+ mAudioTrack->pause();
+ // we have to restart the playback once we start rendering again
+ audioStarted = false;
+ }
mCondition.wait(mMutex);
LOGV("JetPlayer::render(): signal rx'd");
}
@@ -214,12 +219,15 @@ int JetPlayer::render() {
}
p += count * pLibConfig->numChannels;
num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
+
+ // send events that were generated (if any) to the event callback
+ fireEventsFromJetQueue();
}
// update playback state
//LOGV("JetPlayer::render(): updating state");
JET_Status(mEasData, &mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
mPaused = mJetStatus.paused;
mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
@@ -261,9 +269,9 @@ threadExit:
//-------------------------------------------------------------------------------------------------
-// fire up an event if any of the status fields has changed
+// fire up an update if any of the status fields has changed
// precondition: mMutex locked
-void JetPlayer::fireEventOnStatusChange()
+void JetPlayer::fireUpdateOnStatusChange()
{
if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
@@ -303,9 +311,31 @@ void JetPlayer::fireEventOnStatusChange()
//-------------------------------------------------------------------------------------------------
-int JetPlayer::openFile(const char* path)
+// fire up all the JET events in the JET engine queue (until the queue is empty)
+// precondition: mMutex locked
+void JetPlayer::fireEventsFromJetQueue()
+{
+ if(!mEventCallback) {
+ // no callback, just empty the event queue
+ while (JET_GetEvent(mEasData, NULL, NULL)) { }
+ return;
+ }
+
+ EAS_U32 rawEvent;
+ while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
+ mEventCallback(
+ JetPlayer::JET_EVENT,
+ rawEvent,
+ -1,
+ mJavaJetPlayerRef);
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFile(const char* path)
{
- LOGV("JetPlayer::openFile(): path=%s", path);
+ LOGV("JetPlayer::loadFromFile(): path=%s", path);
Mutex::Autolock lock(mMutex);
@@ -326,6 +356,29 @@ int JetPlayer::openFile(const char* path)
return( result );
}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
+{
+ LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
+
+ Mutex::Autolock lock(mMutex);
+
+ mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+ mEasJetFileLoc->fd = fd;
+ mEasJetFileLoc->offset = offset;
+ mEasJetFileLoc->length = length;
+ mEasJetFileLoc->path = NULL;
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ if(result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ return( result );
+}
+
+
//-------------------------------------------------------------------------------------------------
int JetPlayer::closeFile()
{
@@ -348,7 +401,7 @@ int JetPlayer::play()
JET_Status(mEasData, &mJetStatus);
this->dumpJetStatus(&mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
// wake up render thread
LOGV("JetPlayer::play(): wakeup render thread");
@@ -368,7 +421,7 @@ int JetPlayer::pause()
JET_Status(mEasData, &mJetStatus);
this->dumpJetStatus(&mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
return result;
@@ -408,6 +461,14 @@ int JetPlayer::triggerClip(int clipId)
}
//-------------------------------------------------------------------------------------------------
+int JetPlayer::clearQueue()
+{
+ LOGV("JetPlayer::clearQueue");
+ Mutex::Autolock lock(mMutex);
+ return JET_Clear_Queue(mEasData);
+}
+
+//-------------------------------------------------------------------------------------------------
void JetPlayer::dump()
{
LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 584d135..8560593 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -93,11 +93,7 @@ ToneGenerator::ToneGenerator(int streamType, float volume) {
mState = TONE_IDLE;
- if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) {
- LOGE("Unable to marshal AudioFlinger");
- return;
- }
- if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
LOGE("Unable to marshal AudioFlinger");
return;
}
@@ -179,38 +175,42 @@ bool ToneGenerator::startTone(int toneType) {
if (mState == TONE_INIT) {
if (prepareWave()) {
LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
-
+ lResult = true;
mState = TONE_STARTING;
mLock.unlock();
mpAudioTrack->start();
mLock.lock();
if (mState == TONE_STARTING) {
- if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
- LOGE("--- timed out");
+ LOGV("Wait for start callback");
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus != NO_ERROR) {
+ LOGE("--- Immediate start timed out, status %d", lStatus);
mState = TONE_IDLE;
+ lResult = false;
}
}
-
- if (mState == TONE_PLAYING)
- lResult = true;
+ } else {
+ mState == TONE_IDLE;
}
} else {
LOGV("Delayed start\n");
mState = TONE_RESTARTING;
- if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
- if (mState != TONE_INIT) {
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus == NO_ERROR) {
+ if (mState != TONE_IDLE) {
lResult = true;
}
LOGV("cond received");
} else {
- LOGE("--- timed out");
+ LOGE("--- Delayed start timed out, status %d", lStatus);
mState = TONE_IDLE;
}
}
mLock.unlock();
- LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
return lResult;
}
@@ -239,7 +239,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();
}
@@ -275,9 +275,9 @@ bool ToneGenerator::initAudioTrack() {
mpAudioTrack = 0;
}
- // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers of
+ // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack
- = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS*mBufferSize, 0, audioCallback, this, mBufferSize);
+ = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
if (mpAudioTrack == 0) {
LOGE("AudioTrack allocation failed");
@@ -370,6 +370,8 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
break;
default:
LOGV("Extra Cbk");
+ // Force loop exit
+ lNumSmp = 0;
goto audioCallback_EndLoop;
}
@@ -461,8 +463,11 @@ audioCallback_EndLoop:
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
} else {
- lpToneGen->mState = TONE_INIT;
+ LOGW("Cbk restarting prepareWave() failed\n");
+ lpToneGen->mState = TONE_IDLE;
lpToneGen->mpAudioTrack->stop();
+ // Force loop exit
+ lNumSmp = 0;
}
lSignal = true;
break;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index ebdbda8..6b40412 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;
@@ -172,7 +172,7 @@ status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
status_t MediaPlayer::setDataSource(const char *url)
{
LOGV("setDataSource(%s)", url);
- status_t err = UNKNOWN_ERROR;
+ status_t err = BAD_VALUE;
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
@@ -199,7 +199,7 @@ status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return UNKNOWN_ERROR;
+ if (mPlayer == 0) return NO_INIT;
return mPlayer->setVideoSurface(surface->getISurface());
}
@@ -215,11 +215,15 @@ status_t MediaPlayer::prepareAsync_l()
return INVALID_OPERATION;
}
+// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
+// one defined in the Android framework and one provided by the implementation
+// that generated the error. The sync version of prepare returns only 1 error
+// code.
status_t MediaPlayer::prepare()
{
LOGV("prepare");
Mutex::Autolock _l(mLock);
- if (mPrepareSync) return UNKNOWN_ERROR;
+ if (mPrepareSync) return -EALREADY;
mPrepareSync = true;
status_t ret = prepareAsync_l();
if (ret != NO_ERROR) return ret;
@@ -253,7 +257,6 @@ status_t MediaPlayer::start()
status_t ret = mPlayer->start();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
LOGV("playback completed immediately following start()");
@@ -275,7 +278,6 @@ status_t MediaPlayer::stop()
status_t ret = mPlayer->stop();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_STOPPED;
}
@@ -295,7 +297,6 @@ status_t MediaPlayer::pause()
status_t ret = mPlayer->pause();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_PAUSED;
}
@@ -422,7 +423,6 @@ status_t MediaPlayer::reset()
if (ret != NO_ERROR) {
LOGE("reset() failed with return code (%d)", ret);
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_IDLE;
}
@@ -516,7 +516,9 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
}
break;
case MEDIA_ERROR:
- // Always log errors
+ // Always log errors.
+ // ext1: Media framework error code.
+ // ext2: Implementation dependant error code.
LOGE("error (%d, %d)", ext1, ext2);
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
if (mPrepareSync)
@@ -528,6 +530,11 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
send = false;
}
break;
+ case MEDIA_INFO:
+ // ext1: Media framework error code.
+ // ext2: Implementation dependant error code.
+ LOGW("info/warning (%d, %d)", ext1, ext2);
+ break;
case MEDIA_SEEK_COMPLETE:
LOGV("Received seek complete");
if (mSeekPosition != mCurrentPosition) {
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6ee4c0d..23b3b9d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -21,6 +21,7 @@
#include <ui/Surface.h>
#include <media/mediarecorder.h>
#include <utils/IServiceManager.h>
+#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
@@ -42,7 +43,7 @@ status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
if (OK != ret) {
LOGV("setCamera failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -58,12 +59,16 @@ status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
LOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set preview surface without setting the video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
if (OK != ret) {
LOGV("setPreviewSurface failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -84,8 +89,16 @@ status_t MediaRecorder::init()
if (OK != ret) {
LOGV("init failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
+
+ ret = mMediaRecorder->setListener(this);
+ if (OK != ret) {
+ LOGV("setListener failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
mCurrentState = MEDIA_RECORDER_INITIALIZED;
return ret;
}
@@ -117,7 +130,7 @@ status_t MediaRecorder::setVideoSource(int vs)
if (OK != ret) {
LOGV("setVideoSource failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsVideoSourceSet = true;
return ret;
@@ -150,7 +163,7 @@ status_t MediaRecorder::setAudioSource(int as)
if (OK != ret) {
LOGV("setAudioSource failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsAudioSourceSet = true;
return ret;
@@ -167,12 +180,16 @@ status_t MediaRecorder::setOutputFormat(int of)
LOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_RAW_AMR) {
+ LOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setOutputFormat(of);
if (OK != ret) {
LOGE("setOutputFormat failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
return ret;
@@ -185,6 +202,10 @@ status_t MediaRecorder::setVideoEncoder(int ve)
LOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set the video encoder without setting the video source first");
+ return INVALID_OPERATION;
+ }
if (mIsVideoEncoderSet) {
LOGE("video encoder has already been set");
return INVALID_OPERATION;
@@ -198,7 +219,7 @@ status_t MediaRecorder::setVideoEncoder(int ve)
if (OK != ret) {
LOGV("setVideoEncoder failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsVideoEncoderSet = true;
return ret;
@@ -211,6 +232,10 @@ status_t MediaRecorder::setAudioEncoder(int ae)
LOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
}
+ if (!mIsAudioSourceSet) {
+ LOGE("try to set the audio encoder without setting the audio source first");
+ return INVALID_OPERATION;
+ }
if (mIsAudioEncoderSet) {
LOGE("audio encoder has already been set");
return INVALID_OPERATION;
@@ -224,7 +249,7 @@ status_t MediaRecorder::setAudioEncoder(int ae)
if (OK != ret) {
LOGV("setAudioEncoder failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsAudioEncoderSet = true;
return ret;
@@ -248,9 +273,35 @@ 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;
+ return ret;
+ }
+ 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 ret;
}
mIsOutputFileSet = true;
return ret;
@@ -267,12 +318,16 @@ status_t MediaRecorder::setVideoSize(int width, int height)
LOGE("setVideoSize called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set video size without setting video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setVideoSize(width, height);
if (OK != ret) {
LOGE("setVideoSize failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -288,16 +343,37 @@ status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set video frame rate without setting video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
if (OK != ret) {
LOGE("setVideoFrameRate failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
+status_t MediaRecorder::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setParameters(params);
+ if (OK != ret) {
+ LOGE("setParameters(%s) failed: %d", params.string(), ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::prepare()
{
LOGV("prepare");
@@ -306,7 +382,24 @@ 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;
+ }
+ if (mIsAudioSourceSet != mIsAudioEncoderSet) {
+ if (mIsAudioSourceSet) {
+ LOGE("audio source is set, but audio encoder is not set");
+ } else { // must not happen, since setAudioEncoder checks this already
+ LOGE("audio encoder is set, but audio source is not set");
+ }
+ return INVALID_OPERATION;
+ }
+
+ if (mIsVideoSourceSet != mIsVideoEncoderSet) {
+ if (mIsVideoSourceSet) {
+ LOGE("video source is set, but video encoder is not set");
+ } else { // must not happen, since setVideoEncoder checks this already
+ LOGE("video encoder is set, but video source is not set");
+ }
return INVALID_OPERATION;
}
@@ -314,7 +407,7 @@ status_t MediaRecorder::prepare()
if (OK != ret) {
LOGE("prepare failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_PREPARED;
return ret;
@@ -328,7 +421,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;
}
@@ -336,7 +429,7 @@ status_t MediaRecorder::getMaxAmplitude(int* max)
if (OK != ret) {
LOGE("getMaxAmplitude failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -357,7 +450,7 @@ status_t MediaRecorder::start()
if (OK != ret) {
LOGE("start failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_RECORDING;
return ret;
@@ -379,8 +472,13 @@ status_t MediaRecorder::stop()
if (OK != ret) {
LOGE("stop failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
+
+ // FIXME:
+ // stop and reset are semantically different.
+ // We treat them the same for now, and will change this in the future.
+ doCleanUp();
mCurrentState = MEDIA_RECORDER_IDLE;
return ret;
}
@@ -447,7 +545,7 @@ status_t MediaRecorder::doReset()
if (OK != ret) {
LOGE("doReset failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
} else {
mCurrentState = MEDIA_RECORDER_INITIALIZED;
}
@@ -512,5 +610,31 @@ MediaRecorder::~MediaRecorder()
}
}
+status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
+
+ return NO_ERROR;
+}
+
+void MediaRecorder::notify(int msg, int ext1, int ext2)
+{
+ LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+
+ sp<MediaRecorderListener> listener;
+ mLock.lock();
+ listener = mListener;
+ mLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock _l(mNotifyLock);
+ LOGV("callback application");
+ listener->notify(msg, ext1, ext2);
+ LOGV("back from callback");
+ }
+}
+
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5383171..40705c6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -61,113 +61,32 @@ pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
-/*
- When USE_SIGBUS_HANDLER is set to 1, a handler for SIGBUS will be
- installed, which allows us to recover when there is a read error
- when accessing an mmap'ed file. However, since the kernel folks
- don't seem to like it when non kernel folks install signal handlers
- in their own process, this is currently disabled.
- Without the handler, the process hosting this service will die and
- then be restarted. This is mostly OK right now because the process is
- not being shared with any other services, and clients of the service
- will be notified of its death in their MediaPlayer.onErrorListener
- callback, assuming they have installed one, and can then attempt to
- do their own recovery.
- It does open us up to a DOS attack against the media server, where
- a malicious application can trivially force the media server to
- restart continuously.
-*/
-#define USE_SIGBUS_HANDLER 0
+
+namespace android {
// TODO: Temp hack until we can register players
-static const char* MIDI_FILE_EXTS[] =
-{
- ".mid",
- ".smf",
- ".xmf",
- ".imy",
- ".rtttl",
- ".rtx",
- ".ota"
+typedef struct {
+ const char *extension;
+ const player_type playertype;
+} extmap;
+extmap FILE_EXTS [] = {
+ {".mid", SONIVOX_PLAYER},
+ {".midi", SONIVOX_PLAYER},
+ {".smf", SONIVOX_PLAYER},
+ {".xmf", SONIVOX_PLAYER},
+ {".imy", SONIVOX_PLAYER},
+ {".rtttl", SONIVOX_PLAYER},
+ {".rtx", SONIVOX_PLAYER},
+ {".ota", SONIVOX_PLAYER},
+ {".ogg", VORBIS_PLAYER},
+ {".oga", VORBIS_PLAYER},
};
-namespace android {
-
// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
/* static */ const uint32_t MediaPlayerService::AudioOutput::kAudioVideoDelayMs = 96;
/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
-static struct sigaction oldact;
-static pthread_key_t sigbuskey;
-
-static void sigbushandler(int signal, siginfo_t *info, void *context)
-{
- char *faultaddr = (char*) info->si_addr;
- LOGE("SIGBUS at %p\n", faultaddr);
-
- struct mediasigbushandler* h = (struct mediasigbushandler*) pthread_getspecific(sigbuskey);
-
- if (h) {
- if (h->len) {
- if (faultaddr < h->base || faultaddr >= h->base + h->len) {
- // outside specified range, call old handler
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
- }
- }
-
- // no range specified or address was in range
-
- if (h->handlesigbus) {
- if (h->handlesigbus(info, h)) {
- // thread's handler didn't handle the signal
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- }
- return;
- }
-
- if (h->sigbusvar) {
- // map in a zeroed out page so the operation can succeed
- long pagesize = sysconf(_SC_PAGE_SIZE);
- long pagemask = ~(pagesize - 1);
- void * pageaddr = (void*) (((long)(faultaddr)) & pagemask);
-
- void * bar = mmap( pageaddr, pagesize, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
- if (bar == MAP_FAILED) {
- LOGE("couldn't map zero page at %p: %s", pageaddr, strerror(errno));
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
- }
-
- LOGE("setting sigbusvar at %p", h->sigbusvar);
- *(h->sigbusvar) = 1;
- return;
- }
- }
-
- LOGE("SIGBUS: no handler, or improperly configured handler (%p)", h);
-
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
-}
-
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
@@ -177,25 +96,10 @@ MediaPlayerService::MediaPlayerService()
{
LOGV("MediaPlayerService created");
mNextConnId = 1;
-
- pthread_key_create(&sigbuskey, NULL);
-
-
-#if USE_SIGBUS_HANDLER
- struct sigaction act;
- memset(&act,0, sizeof act);
- act.sa_sigaction = sigbushandler;
- act.sa_flags = SA_SIGINFO;
- sigaction(SIGBUS, &act, &oldact);
-#endif
}
MediaPlayerService::~MediaPlayerService()
{
-#if USE_SIGBUS_HANDLER
- sigaction(SIGBUS, &oldact, NULL);
-#endif
- pthread_key_delete(sigbuskey);
LOGV("MediaPlayerService destroyed");
}
@@ -314,6 +218,104 @@ static int myTid() {
#endif
}
+#if defined(__arm__)
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+ size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
+extern "C" void free_malloc_leak_info(uint8_t* info);
+
+void memStatus(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ typedef struct {
+ size_t size;
+ size_t dups;
+ intptr_t * backtrace;
+ } AllocEntry;
+
+ uint8_t *info = NULL;
+ size_t overallSize = 0;
+ size_t infoSize = 0;
+ size_t totalMemory = 0;
+ size_t backtraceSize = 0;
+
+ get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
+ if (info) {
+ uint8_t *ptr = info;
+ size_t count = overallSize / infoSize;
+
+ snprintf(buffer, SIZE, " Allocation count %i\n", count);
+ result.append(buffer);
+
+ AllocEntry * entries = new AllocEntry[count];
+
+ for (size_t i = 0; i < count; i++) {
+ // Each entry should be size_t, size_t, intptr_t[backtraceSize]
+ AllocEntry *e = &entries[i];
+
+ e->size = *reinterpret_cast<size_t *>(ptr);
+ ptr += sizeof(size_t);
+
+ e->dups = *reinterpret_cast<size_t *>(ptr);
+ ptr += sizeof(size_t);
+
+ e->backtrace = reinterpret_cast<intptr_t *>(ptr);
+ ptr += sizeof(intptr_t) * backtraceSize;
+ }
+
+ // Now we need to sort the entries. They come sorted by size but
+ // not by stack trace which causes problems using diff.
+ bool moved;
+ do {
+ moved = false;
+ for (size_t i = 0; i < (count - 1); i++) {
+ AllocEntry *e1 = &entries[i];
+ AllocEntry *e2 = &entries[i+1];
+
+ bool swap = e1->size < e2->size;
+ if (e1->size == e2->size) {
+ for(size_t j = 0; j < backtraceSize; j++) {
+ if (e1->backtrace[j] == e2->backtrace[j]) {
+ continue;
+ }
+ swap = e1->backtrace[j] < e2->backtrace[j];
+ break;
+ }
+ }
+ if (swap) {
+ AllocEntry t = entries[i];
+ entries[i] = entries[i+1];
+ entries[i+1] = t;
+ moved = true;
+ }
+ }
+ } while (moved);
+
+ for (size_t i = 0; i < count; i++) {
+ AllocEntry *e = &entries[i];
+
+ snprintf(buffer, SIZE, "size %8i, dup %4i", e->size, e->dups);
+ result.append(buffer);
+ for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
+ if (ct) {
+ result.append(", ");
+ }
+ snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
+ result.append(buffer);
+ }
+ result.append("\n");
+ }
+
+ delete[] entries;
+ free_malloc_leak_info(info);
+ }
+
+ write(fd, result.string(), result.size());
+}
+#endif
+
status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -396,6 +398,18 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
result.append(buffer);
result.append("\n");
}
+
+#if defined(__arm__)
+ bool dumpMem = false;
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == String16("-m")) {
+ dumpMem = true;
+ }
+ }
+ if (dumpMem) {
+ memStatus(fd, args);
+ }
+#endif
}
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -481,7 +495,7 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length)
locator.offset = offset;
locator.length = length;
EAS_HANDLE eashandle;
- if (EAS_OpenFile(easdata, &locator, &eashandle, NULL) == EAS_SUCCESS) {
+ if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
EAS_CloseFile(easdata, eashandle);
EAS_Shutdown(easdata);
return SONIVOX_PLAYER;
@@ -498,22 +512,16 @@ static player_type getPlayerType(const char* url)
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
- for (int i = 0; i < NELEM(MIDI_FILE_EXTS); ++i) {
- int len = strlen(MIDI_FILE_EXTS[i]);
+ for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
+ int len = strlen(FILE_EXTS[i].extension);
int start = lenURL - len;
if (start > 0) {
- if (!strncmp(url + start, MIDI_FILE_EXTS[i], len)) {
- LOGV("Type is MIDI");
- return SONIVOX_PLAYER;
+ if (!strncmp(url + start, FILE_EXTS[i].extension, len)) {
+ return FILE_EXTS[i].playertype;
}
}
}
- if (strcmp(url + strlen(url) - 4, ".ogg") == 0) {
- LOGV("Type is Vorbis");
- return VORBIS_PLAYER;
- }
-
// Fall through to PV
return PV_PLAYER;
}
@@ -539,7 +547,6 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
- p->setSigBusHandlerStructTLSKey(sigbuskey);
} else {
p.clear();
}
@@ -921,7 +928,7 @@ Exit:
MediaPlayerService::AudioOutput::AudioOutput()
{
mTrack = 0;
- mStreamType = AudioTrack::MUSIC;
+ mStreamType = AudioSystem::MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
mLatency = 0;
@@ -1003,15 +1010,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..5d1887d 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);
@@ -143,6 +154,16 @@ status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
return mRecorder->setVideoFrameRate(frames_per_second);
}
+status_t MediaRecorderClient::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setParameters(params);
+}
+
status_t MediaRecorderClient::prepare()
{
LOGV("prepare");
@@ -247,5 +268,16 @@ MediaRecorderClient::~MediaRecorderClient()
release();
}
+status_t MediaRecorderClient::setListener(const sp<IMediaPlayerClient>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setListener(listener);
+}
+
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 3158017..6a1c2d5 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -36,8 +36,11 @@ 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 setParameters(const String8& params);
+ virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t getMaxAmplitude(int* max);
virtual status_t start();
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index cfad66c..d03caa5 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -40,8 +40,6 @@ static pid_t myTid() { return getpid(); }
// ----------------------------------------------------------------------------
-extern pthread_key_t EAS_sigbuskey;
-
namespace android {
// ----------------------------------------------------------------------------
@@ -60,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");
@@ -132,7 +130,7 @@ status_t MidiFile::setDataSource(const char* path)
mFileLocator.fd = -1;
mFileLocator.offset = 0;
mFileLocator.length = 0;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar);
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
if (result == EAS_SUCCESS) {
updateState();
}
@@ -148,12 +146,6 @@ status_t MidiFile::setDataSource(const char* path)
return NO_ERROR;
}
-status_t MidiFile::setSigBusHandlerStructTLSKey(pthread_key_t key)
-{
- EAS_sigbuskey = key;
- return 0;
-}
-
status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("MidiFile::setDataSource fd=%d", fd);
@@ -168,7 +160,7 @@ status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
mFileLocator.fd = dup(fd);
mFileLocator.offset = offset;
mFileLocator.length = length;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar);
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
updateState();
if (result != EAS_SUCCESS) {
@@ -332,7 +324,7 @@ status_t MidiFile::getDuration(int* duration)
EAS_HANDLE easHandle = NULL;
EAS_RESULT result = EAS_Init(&easData);
if (result == EAS_SUCCESS) {
- result = EAS_OpenFile(easData, &mFileLocator, &easHandle, NULL);
+ result = EAS_OpenFile(easData, &mFileLocator, &easHandle);
}
if (result == EAS_SUCCESS) {
result = EAS_Prepare(easData, easHandle);
@@ -451,8 +443,6 @@ int MidiFile::render() {
LOGV("MidiFile::render");
- struct mediasigbushandler sigbushandler;
-
// allocate render buffer
mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
if (!mAudioBuffer) {
@@ -468,10 +458,6 @@ int MidiFile::render() {
mCondition.signal();
}
- sigbushandler.handlesigbus = NULL;
- sigbushandler.sigbusvar = mMemFailedVar;
- pthread_setspecific(EAS_sigbuskey, &sigbushandler);
-
while (1) {
mMutex.lock();
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 9d2dfdd..302f1cf 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -30,7 +30,6 @@ public:
~MidiFile();
virtual status_t initCheck();
- virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key);
virtual status_t setDataSource(const char* path);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
@@ -57,7 +56,6 @@ private:
Mutex mMutex;
Condition mCondition;
- int* mMemFailedVar;
EAS_DATA_HANDLE mEasData;
EAS_HANDLE mEasHandle;
EAS_PCM* mAudioBuffer;
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index 9a64403..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");
@@ -455,13 +455,15 @@ int VorbisPlayer::render() {
current_section = 0;
numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
} else {
- sendEvent(MEDIA_PLAYBACK_COMPLETE);
mAudioSink->stop();
audioStarted = false;
mRender = false;
mPaused = true;
int endpos = ov_time_tell(&mVorbisFile);
+ LOGV("send MEDIA_PLAYBACK_COMPLETE");
+ sendEvent(MEDIA_PLAYBACK_COMPLETE);
+
// wait until we're started again
LOGV("playback complete - wait for signal");
mCondition.wait(mMutex);