From 5e07b5774c8b376776caa4f5b0a193767697e97e Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:44:00 -0800 Subject: auto import from //branches/cupcake/...@130745 --- include/media/AudioSystem.h | 23 +++- include/media/AudioTrack.h | 1 + include/media/IAudioFlinger.h | 10 ++ include/media/IAudioFlingerClient.h | 55 ++++++++ include/media/JetPlayer.h | 16 ++- include/media/MediaPlayerInterface.h | 32 ----- include/media/PVPlayer.h | 14 +- include/media/ToneGenerator.h | 3 - include/private/opengles/gl_context.h | 1 + media/libmedia/Android.mk | 1 + media/libmedia/AudioRecord.cpp | 18 ++- media/libmedia/AudioSystem.cpp | 55 +++++++- media/libmedia/AudioTrack.cpp | 14 +- media/libmedia/IAudioFlinger.cpp | 50 +++++++ media/libmedia/IAudioFlingerClient.cpp | 81 ++++++++++++ media/libmedia/JetPlayer.cpp | 70 +++++++++- media/libmedia/ToneGenerator.cpp | 8 +- media/libmedia/mediaplayer.cpp | 10 +- media/libmediaplayerservice/MediaPlayerService.cpp | 147 +++------------------ media/libmediaplayerservice/MidiFile.cpp | 20 +-- media/libmediaplayerservice/MidiFile.h | 2 - media/libmediaplayerservice/VorbisPlayer.cpp | 4 +- 22 files changed, 409 insertions(+), 226 deletions(-) create mode 100644 include/media/IAudioFlingerClient.h create mode 100644 media/libmedia/IAudioFlingerClient.cpp diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 77676bf..6bd54ba 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -99,23 +99,31 @@ public: static status_t getOutputSamplingRate(int* samplingRate); static status_t getOutputFrameCount(int* frameCount); static status_t getOutputLatency(uint32_t* latency); + + static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, + size_t* buffSize); // ---------------------------------------------------------------------------- private: - class DeathNotifier: public IBinder::DeathRecipient + class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient { public: - DeathNotifier() { + AudioFlingerClient() { } + // DeathRecipient virtual void binderDied(const wp& who); + + // IAudioFlingerClient + virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency); + }; - static sp gDeathNotifier; + static sp gAudioFlingerClient; - friend class DeathNotifier; + friend class AudioFlingerClient; static Mutex gLock; static sp gAudioFlinger; @@ -123,6 +131,13 @@ private: static int gOutSamplingRate; static int gOutFrameCount; static uint32_t gOutLatency; + + static size_t gInBuffSize; + // previous parameters for recording buffer size queries + static uint32_t gPrevInSamplingRate; + static int gPrevInFormat; + static int gPrevInChannelCount; + }; }; // namespace android diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index fd62daa..5b2bab9 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -51,6 +51,7 @@ public: MUSIC = 3, ALARM = 4, NOTIFICATION = 5, + BLUETOOTH_SCO = 6, NUM_STREAM_TYPES }; diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 69703b2..df601d7 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace android { @@ -107,6 +108,15 @@ public: // Temporary interface, do not use // TODO: Replace with a more generic key:value get/set mechanism virtual status_t setParameter(const char* key, const char* value) = 0; + + // register a current process for audio output change notifications + virtual void registerClient(const sp& client) = 0; + + // retrieve the audio recording buffer size + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0; + + // force AudioFlinger thread out of standby + virtual void wakeUp() = 0; }; diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h new file mode 100644 index 0000000..10c3e0f --- /dev/null +++ b/include/media/IAudioFlingerClient.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef ANDROID_IAUDIOFLINGERCLIENT_H +#define ANDROID_IAUDIOFLINGERCLIENT_H + + +#include +#include + + +namespace android { + +// ---------------------------------------------------------------------------- + +class IAudioFlingerClient : public IInterface +{ +public: + DECLARE_META_INTERFACE(AudioFlingerClient); + + // Notifies a change of audio output from/to hardware to/from A2DP. + virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) = 0; + +}; + + +// ---------------------------------------------------------------------------- + +class BnAudioFlingerClient : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_IAUDIOFLINGERCLIENT_H diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h index 4268170..16764a9 100644 --- a/include/media/JetPlayer.h +++ b/include/media/JetPlayer.h @@ -33,9 +33,12 @@ class JetPlayer { public: - static const int JET_USERID_UPDATE = 1; - static const int JET_NUMQUEUEDSEGMENT_UPDATE = 2; - static const int JET_PAUSE_UPDATE = 3; + // to keep in sync with the JetPlayer class constants + // defined in frameworks/base/media/java/android/media/JetPlayer.java + static const int JET_EVENT = 1; + static const int JET_USERID_UPDATE = 2; + static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3; + static const int JET_PAUSE_UPDATE = 4; JetPlayer(jobject javaJetPlayer, int maxTracks = 32, @@ -44,7 +47,8 @@ public: int init(); int release(); - int openFile(const char* url); + int loadFromFile(const char* url); + int loadFromFD(const int fd, const long long offset, const long long length); int closeFile(); int play(); int pause(); @@ -53,6 +57,7 @@ public: int setMuteFlags(EAS_U32 muteFlags, bool sync); int setMuteFlag(int trackNum, bool muteFlag, bool sync); int triggerClip(int clipId); + int clearQueue(); void setEventCallback(jetevent_callback callback); @@ -62,7 +67,8 @@ public: private: static int renderThread(void*); int render(); - void fireEventOnStatusChange(); + void fireUpdateOnStatusChange(); + void fireEventsFromJetQueue(); JetPlayer() {} // no default constructor void dump(); diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index 30e4578..7f0e7b3 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -17,9 +17,6 @@ #ifndef ANDROID_MEDIAPLAYERINTERFACE_H #define ANDROID_MEDIAPLAYERINTERFACE_H -#include -#include - #ifdef __cplusplus #include @@ -74,7 +71,6 @@ public: virtual ~MediaPlayerBase() {} virtual status_t initCheck() = 0; virtual bool hardwareOutput() = 0; - virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key) { return 0; } virtual status_t setDataSource(const char *url) = 0; virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; virtual status_t setVideoSurface(const sp& surface) = 0; @@ -125,34 +121,6 @@ public: #endif // __cplusplus -// A thread can set the thread local variable identified by the pthread_key_t -// that was passed to the player using the setSigBusHandlerStructTLSKey() -// method to the address of the following structure. -// If 'handlesigbus' is non-NULL, the function it points to will be called, -// and if it returns 0, the signal will be assumed to have been handled, -// and no other action will be taken. If it returns non-zero, the old SIGBUS -// handler will be called. -// If 'handlesigbus is NULL, then sigbusvar must be non NULL. The system's -// SIGBUS handler will map an accessible page filled with zeroes at the -// location that caused the original fault, set the variable pointed to by -// sigbusvar to a non-zero value, and exit (which causes the operation to -// be retried, which should now succeed). -// If base and len are non zero, which is strongly recommended, they will -// be used as additional constraints on the signal handler. That is, when -// specified, the fault address must be in the range specified by base and -// len in order for handlesigbus() to be called or sigbusvar to be set. -// If the fault address is outside of the range, the old SIGBUS handler -// will be called. -struct mediasigbushandler { - int (*handlesigbus)(siginfo_t *, struct mediasigbushandler *); - int *sigbusvar; - char *base; - int len; - // these next two are free for application use - struct mediasigbushandler *next; - void *data; -}; - #endif // ANDROID_MEDIAPLAYERINTERFACE_H diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h index 5f302ed..6d98852 100644 --- a/include/media/PVPlayer.h +++ b/include/media/PVPlayer.h @@ -20,6 +20,12 @@ #include #include +#define MAX_OPENCORE_INSTANCES 25 + +#ifdef MAX_OPENCORE_INSTANCES +#include +#endif + class PlayerDriver; namespace android { @@ -31,7 +37,6 @@ public: virtual ~PVPlayer(); virtual status_t initCheck(); - virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key); virtual status_t setDataSource(const char *url); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setVideoSurface(const sp& surface); @@ -62,10 +67,13 @@ private: char * mDataSourcePath; bool mIsDataSourceSet; sp mSurface; - void * mMemBase; - off_t mMemSize; + int mSharedFd; status_t mInit; int mDuration; + +#ifdef MAX_OPENCORE_INSTANCES + static volatile int32_t sNumInstances; +#endif }; }; // namespace android diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h index 0cfdeec..ec64e4d 100644 --- a/include/media/ToneGenerator.h +++ b/include/media/ToneGenerator.h @@ -85,8 +85,6 @@ private: TONE_RESTARTING // }; - static const unsigned int NUM_PCM_BUFFERS = 2; // Number of AudioTrack pcm buffers - static const unsigned int TONEGEN_MAX_WAVES = 3; static const unsigned int TONEGEN_MAX_SEGMENTS = 4; // Maximun number of elenemts in static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration @@ -127,7 +125,6 @@ private: const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor int mSamplingRate; // AudioFlinger Sampling rate - int mBufferSize; // PCM buffer size in frames AudioTrack *mpAudioTrack; // Pointer to audio track used for playback Mutex mLock; // Mutex to control concurent access to ToneGenerator object from audio callback and application API Mutex mCbkCondLock; // Mutex associated to mWaitCbkCond diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h index 3056139..0c7ad46 100644 --- a/include/private/opengles/gl_context.h +++ b/include/private/opengles/gl_context.h @@ -28,6 +28,7 @@ #include #include +#include namespace android { 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 3d39181..a987b92 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -128,8 +128,22 @@ status_t AudioRecord::set( return BAD_VALUE; } - // TODO: Get input frame count from hardware. - int minFrameCount = 1024*2; + 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; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index a375b55..cf91105 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -15,6 +15,8 @@ */ #define LOG_TAG "AudioSystem" +//#define LOG_NDEBUG 0 + #include #include #include @@ -26,12 +28,17 @@ namespace android { // client singleton for AudioFlinger binder interface Mutex AudioSystem::gLock; sp AudioSystem::gAudioFlinger; -sp AudioSystem::gDeathNotifier; +sp AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; // Cached values int AudioSystem::gOutSamplingRate = 0; int AudioSystem::gOutFrameCount = 0; uint32_t AudioSystem::gOutLatency = 0; +// 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,15 +55,16 @@ const sp& 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(binder); + gAudioFlinger->registerClient(gAudioFlingerClient); // Cache frequently accessed parameters gOutFrameCount = (int)gAudioFlinger->frameCount(); gOutSamplingRate = (int)gAudioFlinger->sampleRate(); @@ -250,7 +258,7 @@ status_t AudioSystem::getOutputSamplingRate(int* samplingRate) const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; // gOutSamplingRate is updated by get_audio_flinger() - } + } *samplingRate = gOutSamplingRate; return NO_ERROR; @@ -261,7 +269,7 @@ status_t AudioSystem::getOutputFrameCount(int* frameCount) if (gOutFrameCount == 0) { const sp& 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; return NO_ERROR; @@ -279,14 +287,38 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency) 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& 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& who) { +void AudioSystem::AudioFlingerClient::binderDied(const wp& who) { Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); AudioSystem::gOutSamplingRate = 0; AudioSystem::gOutFrameCount = 0; AudioSystem::gOutLatency = 0; + AudioSystem::gInBuffSize = 0; if (gAudioErrorCallback) { gAudioErrorCallback(DEAD_OBJECT); @@ -294,6 +326,15 @@ void AudioSystem::DeathNotifier::binderDied(const wp& who) { 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::setErrorCallback(audio_error_callback cb) { Mutex::Autolock _l(AudioSystem::gLock); gAudioErrorCallback = cb; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index f9f8568..63b2012 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -603,13 +603,17 @@ 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?) " + "user=%08x, server=%08x", cblk->user, cblk->server); + mAudioFlinger->wakeUp(); + timeout = 1; + } cblk->waitTimeMs = 0; } - ; + if (--waitCount == 0) { return TIMED_OUT; } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 018ea6c..4215820 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -51,6 +51,9 @@ enum { GET_MIC_MUTE, IS_MUSIC_ACTIVE, SET_PARAMETER, + REGISTER_CLIENT, + GET_INPUTBUFFERSIZE, + WAKE_UP }; class BpAudioFlinger : public BpInterface @@ -303,6 +306,33 @@ public: remote()->transact(SET_PARAMETER, data, &reply); return reply.readInt32(); } + + virtual void registerClient(const sp& 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; + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -470,6 +500,26 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32( setParameter(key, value) ); return NO_ERROR; } break; + case REGISTER_CLIENT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + sp client = interface_cast(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; + 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..d956266 --- /dev/null +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -0,0 +1,81 @@ +/* + * 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 + +#include +#include + +#include + +#include + +namespace android { + +enum { + AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION +}; + +class BpAudioFlingerClient : public BpInterface +{ +public: + BpAudioFlingerClient(const sp& impl) + : BpInterface(impl) + { + } + + void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); + data.writeInt32(frameCount); + data.writeInt32(samplingRate); + data.writeInt32(latency); + 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); + uint32_t frameCount = data.readInt32(); + uint32_t samplingRate = data.readInt32(); + uint32_t latency = data.readInt32(); + audioOutputChanged(frameCount, samplingRate, latency); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index f0edf88..ead24d4 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -214,12 +214,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 +264,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 +306,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 +351,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 +396,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 +416,7 @@ int JetPlayer::pause() JET_Status(mEasData, &mJetStatus); this->dumpJetStatus(&mJetStatus); - fireEventOnStatusChange(); + fireUpdateOnStatusChange(); return result; @@ -408,6 +456,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..fa36460 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -97,10 +97,6 @@ ToneGenerator::ToneGenerator(int streamType, float volume) { LOGE("Unable to marshal AudioFlinger"); return; } - if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) { - LOGE("Unable to marshal AudioFlinger"); - return; - } mStreamType = streamType; mVolume = volume; mpAudioTrack = 0; @@ -275,9 +271,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"); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index ebdbda8..31ff507 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -172,7 +172,7 @@ status_t MediaPlayer::setDataSource(const sp& 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& service(getMediaPlayerService()); if (service != 0) { @@ -199,7 +199,7 @@ status_t MediaPlayer::setVideoSurface(const sp& surface) { LOGV("setVideoSurface"); Mutex::Autolock _l(mLock); - if (mPlayer == 0) return UNKNOWN_ERROR; + if (mPlayer == 0) return NO_INIT; return mPlayer->setVideoSurface(surface->getISurface()); } @@ -219,7 +219,7 @@ 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 +253,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 +274,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 +293,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 +419,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; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 5383171..9e366e2 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"); } @@ -481,7 +385,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 +402,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 +437,6 @@ static sp createPlayer(player_type playerType, void* cookie, if (p != NULL) { if (p->initCheck() == NO_ERROR) { p->setNotifyCallback(cookie, notifyFunc); - p->setSigBusHandlerStructTLSKey(sigbuskey); } else { p.clear(); } diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index cfad66c..7ce2fab 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 { // ---------------------------------------------------------------------------- @@ -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& 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..009d628 100644 --- a/media/libmediaplayerservice/VorbisPlayer.cpp +++ b/media/libmediaplayerservice/VorbisPlayer.cpp @@ -455,13 +455,15 @@ int VorbisPlayer::render() { current_section = 0; numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_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); -- cgit v1.1