summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit89fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5 (patch)
tree28d26f7b71e943e25c7da6e8043d79b7b8d9cf7b
parent15f767b960b38059a74a42a33e16d8df2aec8bc1 (diff)
downloadframeworks_av-89fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5.zip
frameworks_av-89fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5.tar.gz
frameworks_av-89fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5.tar.bz2
auto import from //depot/cupcake/@135843
-rw-r--r--include/media/AudioRecord.h344
-rw-r--r--include/media/AudioSystem.h177
-rw-r--r--include/media/AudioTrack.h419
-rw-r--r--include/media/IAudioFlinger.h141
-rw-r--r--include/media/IAudioFlingerClient.h55
-rw-r--r--include/media/IAudioRecord.h68
-rw-r--r--include/media/IAudioTrack.h84
-rw-r--r--include/media/IMediaMetadataRetriever.h56
-rw-r--r--include/media/IMediaPlayer.h64
-rw-r--r--include/media/IMediaPlayerClient.h48
-rw-r--r--include/media/IMediaPlayerService.h60
-rw-r--r--include/media/IMediaRecorder.h70
-rw-r--r--include/media/JetPlayer.h107
-rw-r--r--include/media/MediaMetadataRetrieverInterface.h52
-rw-r--r--include/media/MediaPlayerInterface.h126
-rw-r--r--include/media/PVMediaRecorder.h65
-rw-r--r--include/media/PVMetadataRetriever.h51
-rw-r--r--include/media/PVPlayer.h81
-rw-r--r--include/media/ToneGenerator.h176
-rw-r--r--include/media/mediametadataretriever.h95
-rw-r--r--include/media/mediaplayer.h144
-rw-r--r--include/media/mediarecorder.h155
-rw-r--r--include/media/mediascanner.h85
-rw-r--r--include/media/thread_init.h25
-rw-r--r--include/private/media/AudioTrackShared.h83
-rw-r--r--include/private/media/VideoFrame.h127
-rw-r--r--include/private/opengles/gl_context.h632
-rw-r--r--include/private/ui/LayerState.h75
-rw-r--r--include/private/ui/SharedState.h168
-rw-r--r--include/private/ui/SurfaceFlingerSynchro.h76
-rw-r--r--include/private/utils/Static.h58
-rw-r--r--include/private/utils/binder_module.h148
-rw-r--r--include/private/utils/futex_synchro.h60
-rw-r--r--media/libmedia/Android.mk39
-rw-r--r--media/libmedia/AudioRecord.cpp574
-rw-r--r--media/libmedia/AudioSystem.cpp383
-rw-r--r--media/libmedia/AudioTrack.cpp1021
-rw-r--r--media/libmedia/IAudioFlinger.cpp553
-rw-r--r--media/libmedia/IAudioFlingerClient.cpp77
-rw-r--r--media/libmedia/IAudioRecord.cpp100
-rw-r--r--media/libmedia/IAudioTrack.cpp140
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp218
-rw-r--r--media/libmedia/IMediaPlayer.cpp275
-rw-r--r--media/libmedia/IMediaPlayerClient.cpp77
-rw-r--r--media/libmedia/IMediaPlayerService.cpp198
-rw-r--r--media/libmedia/IMediaRecorder.cpp417
-rw-r--r--media/libmedia/JetPlayer.cpp489
-rw-r--r--media/libmedia/MODULE_LICENSE_APACHE20
-rw-r--r--media/libmedia/NOTICE190
-rw-r--r--media/libmedia/ToneGenerator.cpp730
-rw-r--r--media/libmedia/mediametadataretriever.cpp188
-rw-r--r--media/libmedia/mediaplayer.cpp624
-rw-r--r--media/libmedia/mediarecorder.cpp617
-rw-r--r--media/libmediaplayerservice/Android.mk36
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp1173
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h238
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp273
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h66
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp250
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h71
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp558
-rw-r--r--media/libmediaplayerservice/MidiFile.h77
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.cpp529
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.h91
-rw-r--r--media/mediaserver/Android.mk22
-rw-r--r--media/mediaserver/main_mediaserver.cpp45
66 files changed, 14514 insertions, 0 deletions
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
new file mode 100644
index 0000000..ff64855
--- /dev/null
+++ b/include/media/AudioRecord.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2008 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 AUDIORECORD_H_
+#define AUDIORECORD_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioRecord.h>
+#include <media/AudioTrack.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioRecord
+{
+public:
+
+ enum stream_type {
+ DEFAULT_INPUT =-1,
+ MIC_INPUT = 0,
+ NUM_STREAM_TYPES
+ };
+
+ static const int DEFAULT_SAMPLE_RATE = 8000;
+
+ /* Events used by AudioRecord callback function (callback_t).
+ *
+ * to keep in sync with frameworks/base/media/java/android/media/AudioRecord.java
+ */
+ enum event_type {
+ EVENT_MORE_DATA = 0, // Request to reqd more data from PCM buffer.
+ EVENT_OVERRUN = 1, // PCM buffer overrun occured.
+ EVENT_MARKER = 2, // Record head is at the specified marker position
+ // (See setMarkerPosition()).
+ EVENT_NEW_POS = 3, // Record head is at a new position
+ // (See setPositionUpdatePeriod()).
+ };
+
+ /* Create Buffer on the stack and pass it to obtainBuffer()
+ * and releaseBuffer().
+ */
+
+ class Buffer
+ {
+ public:
+ enum {
+ MUTE = 0x00000001
+ };
+ uint32_t flags;
+ int channelCount;
+ int format;
+ size_t frameCount;
+ size_t size;
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ };
+
+ /* These are static methods to control the system-wide AudioFlinger
+ * only privileged processes can have access to them
+ */
+
+// static status_t setMasterMute(bool mute);
+
+ /* As a convenience, if a callback is supplied, a handler thread
+ * is automatically created with the appropriate priority. This thread
+ * invokes the callback when a new buffer becomes ready or an overrun condition occurs.
+ * Parameters:
+ *
+ * event: type of event notified (see enum AudioRecord::event_type).
+ * user: Pointer to context for use by the callback receiver.
+ * info: Pointer to optional parameter according to event type:
+ * - EVENT_MORE_DATA: pointer to AudioRecord::Buffer struct. The callback must not read
+ * more bytes than indicated by 'size' field and update 'size' if less bytes are
+ * read.
+ * - EVENT_OVERRUN: unused.
+ * - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
+ * - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
+ */
+
+ typedef void (*callback_t)(int event, void* user, void *info);
+
+ /* Constructs an uninitialized AudioRecord. No connection with
+ * AudioFlinger takes place.
+ */
+ AudioRecord();
+
+ /* Creates an AudioRecord track and registers it with AudioFlinger.
+ * Once created, the track needs to be started before it can be used.
+ * Unspecified values are set to the audio hardware's current
+ * values.
+ *
+ * Parameters:
+ *
+ * streamType: Select the audio input to record to (e.g. AudioRecord::MIC_INPUT).
+ * sampleRate: Track sampling rate in Hz.
+ * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * 16 bits per sample).
+ * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * frameCount: Total size of track PCM buffer in frames. This defines the
+ * latency of the track.
+ * flags: A bitmask of acoustic values from enum record_flags. It enables
+ * AGC, NS, and IIR.
+ * cbf: Callback function. If not null, this function is called periodically
+ * to provide new PCM data.
+ * notificationFrames: The callback function is called each time notificationFrames PCM
+ * frames are ready in record track output buffer.
+ * user Context for use by the callback receiver.
+ */
+
+ enum record_flags {
+ RECORD_AGC_ENABLE = AudioSystem::AGC_ENABLE,
+ RECORD_NS_ENABLE = AudioSystem::NS_ENABLE,
+ RECORD_IIR_ENABLE = AudioSystem::TX_IIR_ENABLE
+ };
+
+ AudioRecord(int streamType,
+ uint32_t sampleRate = 0,
+ int format = 0,
+ int channelCount = 0,
+ int frameCount = 0,
+ uint32_t flags = 0,
+ callback_t cbf = 0,
+ void* user = 0,
+ int notificationFrames = 0);
+
+
+ /* Terminates the AudioRecord and unregisters it from AudioFlinger.
+ * Also destroys all resources assotiated with the AudioRecord.
+ */
+ ~AudioRecord();
+
+
+ /* Initialize an uninitialized AudioRecord.
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful intialization
+ * - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
+ * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - NO_INIT: audio server or audio hardware not initialized
+ * - PERMISSION_DENIED: recording is not allowed for the requesting process
+ * */
+ status_t set(int streamType = 0,
+ uint32_t sampleRate = 0,
+ int format = 0,
+ int channelCount = 0,
+ int frameCount = 0,
+ uint32_t flags = 0,
+ callback_t cbf = 0,
+ void* user = 0,
+ int notificationFrames = 0,
+ bool threadCanCallJava = false);
+
+
+ /* Result of constructing the AudioRecord. This must be checked
+ * before using any AudioRecord API (except for set()), using
+ * an uninitialized AudioRecord produces undefined results.
+ * See set() method above for possible return codes.
+ */
+ status_t initCheck() const;
+
+ /* Returns this track's latency in milliseconds.
+ * This includes the latency due to AudioRecord buffer size
+ * and audio hardware driver.
+ */
+ uint32_t latency() const;
+
+ /* getters, see constructor */
+
+ uint32_t sampleRate() const;
+ int format() const;
+ int channelCount() const;
+ uint32_t frameCount() const;
+ int frameSize() const;
+
+
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ */
+ status_t start();
+
+ /* Stop a track. If set, the callback will cease being called and
+ * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
+ * and will fill up buffers until the pool is exhausted.
+ */
+ status_t stop();
+ bool stopped() const;
+
+ /* get sample rate for this track
+ */
+ uint32_t getSampleRate();
+
+ /* Sets marker position. When record reaches the number of frames specified,
+ * a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
+ * with marker == 0 cancels marker notification callback.
+ * If the AudioRecord has been opened with no callback function associated,
+ * the operation will fail.
+ *
+ * Parameters:
+ *
+ * marker: marker position expressed in frames.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioRecord has no callback installed.
+ */
+ status_t setMarkerPosition(uint32_t marker);
+ status_t getMarkerPosition(uint32_t *marker);
+
+
+ /* Sets position update period. Every time the number of frames specified has been recorded,
+ * a callback with event type EVENT_NEW_POS is called.
+ * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+ * callback.
+ * If the AudioRecord has been opened with no callback function associated,
+ * the operation will fail.
+ *
+ * Parameters:
+ *
+ * updatePeriod: position update notification period expressed in frames.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioRecord has no callback installed.
+ */
+ status_t setPositionUpdatePeriod(uint32_t updatePeriod);
+ status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
+
+
+ /* Gets record head position. The position is the total number of frames
+ * recorded since record start.
+ *
+ * Parameters:
+ *
+ * position: Address where to return record head position within AudioRecord buffer.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - BAD_VALUE: position is NULL
+ */
+ status_t getPosition(uint32_t *position);
+
+
+
+ /* obtains a buffer of "frameCount" frames. The buffer must be
+ * filled entirely. If the track is stopped, obtainBuffer() returns
+ * STOPPED instead of NO_ERROR as long as there are buffers availlable,
+ * at which point NO_MORE_BUFFERS is returned.
+ * Buffers will be returned until the pool (buffercount())
+ * is exhausted, at which point obtainBuffer() will either block
+ * or return WOULD_BLOCK depending on the value of the "blocking"
+ * parameter.
+ */
+
+ enum {
+ NO_MORE_BUFFERS = 0x80000001,
+ STOPPED = 1
+ };
+
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+ void releaseBuffer(Buffer* audioBuffer);
+
+
+ /* As a convenience we provide a read() interface to the audio buffer.
+ * This is implemented on top of lockBuffer/unlockBuffer.
+ */
+ ssize_t read(void* buffer, size_t size);
+
+private:
+ /* copying audio tracks is not allowed */
+ AudioRecord(const AudioRecord& other);
+ AudioRecord& operator = (const AudioRecord& other);
+
+ /* a small internal class to handle the callback */
+ class ClientRecordThread : public Thread
+ {
+ public:
+ ClientRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
+ private:
+ friend class AudioRecord;
+ virtual bool threadLoop();
+ virtual status_t readyToRun() { return NO_ERROR; }
+ virtual void onFirstRef() {}
+ AudioRecord& mReceiver;
+ Mutex mLock;
+ };
+
+ bool processAudioBuffer(const sp<ClientRecordThread>& thread);
+
+ sp<IAudioFlinger> mAudioFlinger;
+ sp<IAudioRecord> mAudioRecord;
+ sp<IMemory> mCblkMemory;
+ sp<ClientRecordThread> mClientRecordThread;
+ Mutex mRecordThreadLock;
+
+ uint32_t mSampleRate;
+ uint32_t mFrameCount;
+
+ audio_track_cblk_t* mCblk;
+ uint8_t mFormat;
+ uint8_t mChannelCount;
+ uint8_t mReserved[2];
+ status_t mStatus;
+ uint32_t mLatency;
+
+ volatile int32_t mActive;
+
+ callback_t mCbf;
+ void* mUserData;
+ uint32_t mNotificationFrames;
+ uint32_t mRemainingFrames;
+ uint32_t mMarkerPosition;
+ uint32_t mNewPosition;
+ uint32_t mUpdatePeriod;
+};
+
+}; // namespace android
+
+#endif /*AUDIORECORD_H_*/
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
new file mode 100644
index 0000000..77c90ba
--- /dev/null
+++ b/include/media/AudioSystem.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008 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_AUDIOSYSTEM_H_
+#define ANDROID_AUDIOSYSTEM_H_
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <media/IAudioFlinger.h>
+
+namespace android {
+
+typedef void (*audio_error_callback)(status_t err);
+
+class AudioSystem
+{
+public:
+
+ enum stream_type {
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ NUM_STREAM_TYPES
+ };
+
+ enum audio_output_type {
+ AUDIO_OUTPUT_DEFAULT =-1,
+ AUDIO_OUTPUT_HARDWARE = 0,
+ AUDIO_OUTPUT_A2DP = 1,
+ NUM_AUDIO_OUTPUT_TYPES
+ };
+
+ enum audio_format {
+ FORMAT_DEFAULT = 0,
+ PCM_16_BIT,
+ PCM_8_BIT,
+ INVALID_FORMAT
+ };
+
+ enum audio_mode {
+ MODE_INVALID = -2,
+ MODE_CURRENT = -1,
+ MODE_NORMAL = 0,
+ MODE_RINGTONE,
+ MODE_IN_CALL,
+ NUM_MODES // not a valid entry, denotes end-of-list
+ };
+
+ enum audio_routes {
+ ROUTE_EARPIECE = (1 << 0),
+ ROUTE_SPEAKER = (1 << 1),
+ ROUTE_BLUETOOTH_SCO = (1 << 2),
+ ROUTE_HEADSET = (1 << 3),
+ ROUTE_BLUETOOTH_A2DP = (1 << 4),
+ ROUTE_ALL = -1UL,
+ };
+
+ enum audio_in_acoustics {
+ AGC_ENABLE = 0x0001,
+ AGC_DISABLE = 0,
+ NS_ENABLE = 0x0002,
+ NS_DISABLE = 0,
+ TX_IIR_ENABLE = 0x0004,
+ TX_DISABLE = 0
+ };
+
+ /* These are static methods to control the system-wide AudioFlinger
+ * only privileged processes can have access to them
+ */
+
+ // routing helper functions
+ static status_t speakerphone(bool state);
+ static status_t isSpeakerphoneOn(bool* state);
+ static status_t bluetoothSco(bool state);
+ static status_t isBluetoothScoOn(bool* state);
+ static status_t muteMicrophone(bool state);
+ static status_t isMicrophoneMuted(bool *state);
+
+ static status_t setMasterVolume(float value);
+ static status_t setMasterMute(bool mute);
+ static status_t getMasterVolume(float* volume);
+ static status_t getMasterMute(bool* mute);
+
+ static status_t setStreamVolume(int stream, float value);
+ static status_t setStreamMute(int stream, bool mute);
+ static status_t getStreamVolume(int stream, float* volume);
+ static status_t getStreamMute(int stream, bool* mute);
+
+ static status_t setMode(int mode);
+ static status_t getMode(int* mode);
+
+ static status_t setRouting(int mode, uint32_t routes, uint32_t mask);
+ static status_t getRouting(int mode, uint32_t* routes);
+
+ static status_t isMusicActive(bool *state);
+
+ // Temporary interface, do not use
+ // TODO: Replace with a more generic key:value get/set mechanism
+ static status_t setParameter(const char* key, const char* value);
+
+ static void setErrorCallback(audio_error_callback cb);
+
+ // helper function to obtain AudioFlinger service handle
+ static const sp<IAudioFlinger>& get_audio_flinger();
+
+ static float linearToLog(int volume);
+ static int logToLinear(float volume);
+
+ static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT);
+ static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT);
+ static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
+
+ static bool routedToA2dpOutput(int streamType);
+
+ static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+ size_t* buffSize);
+
+ // ----------------------------------------------------------------------------
+
+private:
+
+ class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
+ {
+ public:
+ AudioFlingerClient() {
+ }
+
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ // IAudioFlingerClient
+ virtual void a2dpEnabledChanged(bool enabled);
+
+ };
+ static int getOutput(int streamType);
+
+ static sp<AudioFlingerClient> gAudioFlingerClient;
+
+ friend class AudioFlingerClient;
+
+ static Mutex gLock;
+ static sp<IAudioFlinger> gAudioFlinger;
+ static audio_error_callback gAudioErrorCallback;
+ static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+ static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+ static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+ static bool gA2dpEnabled;
+
+ static size_t gInBuffSize;
+ // previous parameters for recording buffer size queries
+ static uint32_t gPrevInSamplingRate;
+ static int gPrevInFormat;
+ static int gPrevInChannelCount;
+
+};
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIOSYSTEM_H_*/
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
new file mode 100644
index 0000000..659f5f8
--- /dev/null
+++ b/include/media/AudioTrack.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2007 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_AUDIOTRACK_H
+#define ANDROID_AUDIOTRACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioTrack.h>
+#include <media/AudioSystem.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class audio_track_cblk_t;
+
+// ----------------------------------------------------------------------------
+
+class AudioTrack
+{
+public:
+ enum channel_index {
+ MONO = 0,
+ LEFT = 0,
+ RIGHT = 1
+ };
+
+ /* Events used by AudioTrack callback function (audio_track_cblk_t).
+ */
+ enum event_type {
+ EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer.
+ EVENT_UNDERRUN = 1, // PCM buffer underrun occured.
+ EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0.
+ EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()).
+ EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()).
+ EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
+ };
+
+ /* Create Buffer on the stack and pass it to obtainBuffer()
+ * and releaseBuffer().
+ */
+
+ class Buffer
+ {
+ public:
+ enum {
+ MUTE = 0x00000001
+ };
+ uint32_t flags;
+ int channelCount;
+ int format;
+ size_t frameCount;
+ size_t size;
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ };
+
+
+ /* As a convenience, if a callback is supplied, a handler thread
+ * is automatically created with the appropriate priority. This thread
+ * invokes the callback when a new buffer becomes availlable or an underrun condition occurs.
+ * Parameters:
+ *
+ * event: type of event notified (see enum AudioTrack::event_type).
+ * user: Pointer to context for use by the callback receiver.
+ * info: Pointer to optional parameter according to event type:
+ * - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
+ * more bytes than indicated by 'size' field and update 'size' if less bytes are
+ * written.
+ * - EVENT_UNDERRUN: unused.
+ * - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
+ * - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
+ * - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
+ * - EVENT_BUFFER_END: unused.
+ */
+
+ typedef void (*callback_t)(int event, void* user, void *info);
+
+ /* Constructs an uninitialized AudioTrack. No connection with
+ * AudioFlinger takes place.
+ */
+ AudioTrack();
+
+ /* Creates an audio track and registers it with AudioFlinger.
+ * Once created, the track needs to be started before it can be used.
+ * Unspecified values are set to the audio hardware's current
+ * values.
+ *
+ * Parameters:
+ *
+ * streamType: Select the type of audio stream this track is attached to
+ * (e.g. AudioSystem::MUSIC).
+ * sampleRate: Track sampling rate in Hz.
+ * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * 16 bits per sample).
+ * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * frameCount: Total size of track PCM buffer in frames. This defines the
+ * latency of the track.
+ * flags: Reserved for future use.
+ * cbf: Callback function. If not null, this function is called periodically
+ * to request new PCM data.
+ * notificationFrames: The callback function is called each time notificationFrames PCM
+ * frames have been comsumed from track input buffer.
+ * user Context for use by the callback receiver.
+ */
+
+ AudioTrack( int streamType,
+ uint32_t sampleRate = 0,
+ int format = 0,
+ int channelCount = 0,
+ int frameCount = 0,
+ uint32_t flags = 0,
+ callback_t cbf = 0,
+ void* user = 0,
+ int notificationFrames = 0);
+
+ /* Creates an audio track and registers it with AudioFlinger. With this constructor,
+ * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
+ * identified by the argument sharedBuffer. This prototype is for static buffer playback.
+ * PCM data must be present into memory before the AudioTrack is started.
+ * The Write() and Flush() methods are not supported in this case.
+ * It is recommented to pass a callback function to be notified of playback end by an
+ * EVENT_UNDERRUN event.
+ */
+
+ AudioTrack( int streamType,
+ uint32_t sampleRate = 0,
+ int format = 0,
+ int channelCount = 0,
+ const sp<IMemory>& sharedBuffer = 0,
+ uint32_t flags = 0,
+ callback_t cbf = 0,
+ void* user = 0,
+ int notificationFrames = 0);
+
+ /* Terminates the AudioTrack and unregisters it from AudioFlinger.
+ * Also destroys all resources assotiated with the AudioTrack.
+ */
+ ~AudioTrack();
+
+
+ /* Initialize an uninitialized AudioTrack.
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful intialization
+ * - INVALID_OPERATION: AudioTrack is already intitialized
+ * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - NO_INIT: audio server or audio hardware not initialized
+ * */
+ status_t set(int streamType =-1,
+ uint32_t sampleRate = 0,
+ int format = 0,
+ int channelCount = 0,
+ int frameCount = 0,
+ uint32_t flags = 0,
+ callback_t cbf = 0,
+ void* user = 0,
+ int notificationFrames = 0,
+ const sp<IMemory>& sharedBuffer = 0,
+ bool threadCanCallJava = false);
+
+
+ /* Result of constructing the AudioTrack. This must be checked
+ * before using any AudioTrack API (except for set()), using
+ * an uninitialized AudioTrack produces undefined results.
+ * See set() method above for possible return codes.
+ */
+ status_t initCheck() const;
+
+ /* Returns this track's latency in milliseconds.
+ * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
+ * and audio hardware driver.
+ */
+ uint32_t latency() const;
+
+ /* getters, see constructor */
+
+ int streamType() const;
+ uint32_t sampleRate() const;
+ int format() const;
+ int channelCount() const;
+ uint32_t frameCount() const;
+ int frameSize() const;
+ sp<IMemory>& sharedBuffer();
+
+
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ */
+ void start();
+
+ /* Stop a track. If set, the callback will cease being called and
+ * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
+ * and will fill up buffers until the pool is exhausted.
+ */
+ void stop();
+ bool stopped() const;
+
+ /* flush a stopped track. All pending buffers are discarded.
+ * This function has no effect if the track is not stoped.
+ */
+ void flush();
+
+ /* Pause a track. If set, the callback will cease being called and
+ * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
+ * and will fill up buffers until the pool is exhausted.
+ */
+ void pause();
+
+ /* mute or unmutes this track.
+ * While mutted, the callback, if set, is still called.
+ */
+ void mute(bool);
+ bool muted() const;
+
+
+ /* set volume for this track, mostly used for games' sound effects
+ */
+ void setVolume(float left, float right);
+ void getVolume(float* left, float* right);
+
+ /* set sample rate for this track, mostly used for games' sound effects
+ */
+ void setSampleRate(int sampleRate);
+ uint32_t getSampleRate();
+
+ /* Enables looping and sets the start and end points of looping.
+ *
+ * Parameters:
+ *
+ * loopStart: loop start expressed as the number of PCM frames played since AudioTrack start.
+ * loopEnd: loop end expressed as the number of PCM frames played since AudioTrack start.
+ * loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or
+ * active loop. loopCount = -1 means infinite looping.
+ *
+ * For proper operation the following condition must be respected:
+ * (loopEnd-loopStart) <= framecount()
+ */
+ status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+ status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
+
+
+ /* Sets marker position. When playback reaches the number of frames specified, a callback with event
+ * type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification
+ * callback.
+ * If the AudioTrack has been opened with no callback function associated, the operation will fail.
+ *
+ * Parameters:
+ *
+ * marker: marker position expressed in frames.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioTrack has no callback installed.
+ */
+ status_t setMarkerPosition(uint32_t marker);
+ status_t getMarkerPosition(uint32_t *marker);
+
+
+ /* Sets position update period. Every time the number of frames specified has been played,
+ * a callback with event type EVENT_NEW_POS is called.
+ * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+ * callback.
+ * If the AudioTrack has been opened with no callback function associated, the operation will fail.
+ *
+ * Parameters:
+ *
+ * updatePeriod: position update notification period expressed in frames.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioTrack has no callback installed.
+ */
+ status_t setPositionUpdatePeriod(uint32_t updatePeriod);
+ status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
+
+
+ /* Sets playback head position within AudioTrack buffer. The new position is specified
+ * in number of frames.
+ * This method must be called with the AudioTrack in paused or stopped state.
+ * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames.
+ * Therefore using this method makes sense only when playing a "static" audio buffer
+ * as opposed to streaming.
+ * The getPosition() method on the other hand returns the total number of frames played since
+ * playback start.
+ *
+ * Parameters:
+ *
+ * position: New playback head position within AudioTrack buffer.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioTrack is not stopped.
+ * - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer
+ */
+ status_t setPosition(uint32_t position);
+ status_t getPosition(uint32_t *position);
+
+ /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
+ * rewriting the buffer before restarting playback after a stop.
+ * This method must be called with the AudioTrack in paused or stopped state.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: the AudioTrack is not stopped.
+ */
+ status_t reload();
+
+ /* obtains a buffer of "frameCount" frames. The buffer must be
+ * filled entirely. If the track is stopped, obtainBuffer() returns
+ * STOPPED instead of NO_ERROR as long as there are buffers availlable,
+ * at which point NO_MORE_BUFFERS is returned.
+ * Buffers will be returned until the pool (buffercount())
+ * is exhausted, at which point obtainBuffer() will either block
+ * or return WOULD_BLOCK depending on the value of the "blocking"
+ * parameter.
+ */
+
+ enum {
+ NO_MORE_BUFFERS = 0x80000001,
+ STOPPED = 1
+ };
+
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+ void releaseBuffer(Buffer* audioBuffer);
+
+
+ /* As a convenience we provide a write() interface to the audio buffer.
+ * This is implemented on top of lockBuffer/unlockBuffer. For best
+ * performance
+ *
+ */
+ ssize_t write(const void* buffer, size_t size);
+
+ /*
+ * Dumps the state of an audio track.
+ */
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+ /* copying audio tracks is not allowed */
+ AudioTrack(const AudioTrack& other);
+ AudioTrack& operator = (const AudioTrack& other);
+
+ /* a small internal class to handle the callback */
+ class AudioTrackThread : public Thread
+ {
+ public:
+ AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
+ private:
+ friend class AudioTrack;
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+ AudioTrack& mReceiver;
+ Mutex mLock;
+ };
+
+ bool processAudioBuffer(const sp<AudioTrackThread>& thread);
+
+ sp<IAudioFlinger> mAudioFlinger;
+ sp<IAudioTrack> mAudioTrack;
+ sp<IMemory> mCblkMemory;
+ sp<AudioTrackThread> mAudioTrackThread;
+
+ float mVolume[2];
+ uint32_t mSampleRate;
+ uint32_t mFrameCount;
+
+ audio_track_cblk_t* mCblk;
+ uint8_t mStreamType;
+ uint8_t mFormat;
+ uint8_t mChannelCount;
+ uint8_t mMuted;
+ status_t mStatus;
+ uint32_t mLatency;
+
+ volatile int32_t mActive;
+
+ callback_t mCbf;
+ void* mUserData;
+ uint32_t mNotificationFrames;
+ sp<IMemory> mSharedBuffer;
+ int mLoopCount;
+ uint32_t mRemainingFrames;
+ uint32_t mMarkerPosition;
+ uint32_t mNewPosition;
+ uint32_t mUpdatePeriod;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOTRACK_H
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
new file mode 100644
index 0000000..6f13fe0
--- /dev/null
+++ b/include/media/IAudioFlinger.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2007 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_IAUDIOFLINGER_H
+#define ANDROID_IAUDIOFLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/IAudioFlingerClient.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioFlinger : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioFlinger);
+
+ /* create an audio track and registers it with AudioFlinger.
+ * return null if the track cannot be created.
+ */
+ virtual sp<IAudioTrack> createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status) = 0;
+
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ status_t *status) = 0;
+
+ /* query the audio hardware state. This state never changes,
+ * and therefore can be cached.
+ */
+ virtual uint32_t sampleRate(int output) const = 0;
+ virtual int channelCount(int output) const = 0;
+ virtual int format(int output) const = 0;
+ virtual size_t frameCount(int output) const = 0;
+ virtual uint32_t latency(int output) const = 0;
+
+ /* set/get the audio hardware state. This will probably be used by
+ * the preference panel, mostly.
+ */
+ virtual status_t setMasterVolume(float value) = 0;
+ virtual status_t setMasterMute(bool muted) = 0;
+
+ virtual float masterVolume() const = 0;
+ virtual bool masterMute() const = 0;
+
+ /* set/get stream type state. This will probably be used by
+ * the preference panel, mostly.
+ */
+ virtual status_t setStreamVolume(int stream, float value) = 0;
+ virtual status_t setStreamMute(int stream, bool muted) = 0;
+
+ virtual float streamVolume(int stream) const = 0;
+ virtual bool streamMute(int stream) const = 0;
+
+ // set/get audio routing
+ virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask) = 0;
+ virtual uint32_t getRouting(int mode) const = 0;
+
+ // set/get audio mode
+ virtual status_t setMode(int mode) = 0;
+ virtual int getMode() const = 0;
+
+ // mic mute/state
+ virtual status_t setMicMute(bool state) = 0;
+ virtual bool getMicMute() const = 0;
+
+ // is a music stream active?
+ virtual bool isMusicActive() const = 0;
+
+ // pass a generic configuration parameter to libaudio
+ // 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<IAudioFlingerClient>& 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;
+
+ // is A2DP output enabled
+ virtual bool isA2dpEnabled() const = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioFlinger : public BnInterface<IAudioFlinger>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOFLINGER_H
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
new file mode 100644
index 0000000..c3deb0b
--- /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 <utils/RefBase.h>
+#include <utils/IInterface.h>
+
+
+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 a2dpEnabledChanged(bool enabled) = 0;
+
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioFlingerClient : public BnInterface<IAudioFlingerClient>
+{
+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/IAudioRecord.h b/include/media/IAudioRecord.h
new file mode 100644
index 0000000..9d45d2d
--- /dev/null
+++ b/include/media/IAudioRecord.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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 IAUDIORECORD_H_
+#define IAUDIORECORD_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioRecord : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioRecord);
+
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ */
+ virtual status_t start() = 0;
+
+ /* Stop a track. If set, the callback will cease being called and
+ * obtainBuffer will return an error. Buffers that are already released
+ * will be processed, unless flush() is called.
+ */
+ virtual void stop() = 0;
+
+ /* get this tracks control block */
+ virtual sp<IMemory> getCblk() const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnAudioRecord : public BnInterface<IAudioRecord>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /*IAUDIORECORD_H_*/
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
new file mode 100644
index 0000000..12f2111
--- /dev/null
+++ b/include/media/IAudioTrack.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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_IAUDIOTRACK_H
+#define ANDROID_IAUDIOTRACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/IInterface.h>
+#include <utils/IMemory.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioTrack : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioTrack);
+
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ */
+ virtual status_t start() = 0;
+
+ /* Stop a track. If set, the callback will cease being called and
+ * obtainBuffer will return an error. Buffers that are already released
+ * will be processed, unless flush() is called.
+ */
+ virtual void stop() = 0;
+
+ /* flush a stopped track. All pending buffers are discarded.
+ * This function has no effect if the track is not stoped.
+ */
+ virtual void flush() = 0;
+
+ /* mute or unmutes this track.
+ * While mutted, the callback, if set, is still called.
+ */
+ virtual void mute(bool) = 0;
+
+ /* Pause a track. If set, the callback will cease being called and
+ * obtainBuffer will return an error. Buffers that are already released
+ * will be processed, unless flush() is called.
+ */
+ virtual void pause() = 0;
+
+ /* get this tracks control block */
+ virtual sp<IMemory> getCblk() const = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnAudioTrack : public BnInterface<IAudioTrack>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOTRACK_H
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
new file mode 100644
index 0000000..c677e83
--- /dev/null
+++ b/include/media/IMediaMetadataRetriever.h
@@ -0,0 +1,56 @@
+/*
+**
+** Copyright (C) 2008 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_IMEDIAMETADATARETRIEVER_H
+#define ANDROID_IMEDIAMETADATARETRIEVER_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+namespace android {
+
+class IMediaMetadataRetriever: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaMetadataRetriever);
+ virtual void disconnect() = 0;
+ virtual status_t setDataSource(const char* srcUrl) = 0;
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setMode(int mode) = 0;
+ virtual status_t getMode(int* mode) const = 0;
+ virtual sp<IMemory> captureFrame() = 0;
+ virtual sp<IMemory> extractAlbumArt() = 0;
+ virtual const char* extractMetadata(int keyCode) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaMetadataRetriever: public BnInterface<IMediaMetadataRetriever>
+{
+public:
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIAMETADATARETRIEVER_H
+
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
new file mode 100644
index 0000000..a683e74
--- /dev/null
+++ b/include/media/IMediaPlayer.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 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_IMEDIAPLAYER_H
+#define ANDROID_IMEDIAPLAYER_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+namespace android {
+
+class ISurface;
+
+class IMediaPlayer: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaPlayer);
+
+ virtual void disconnect() = 0;
+
+ virtual status_t setVideoSurface(const sp<ISurface>& surface) = 0;
+ virtual status_t prepareAsync() = 0;
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t pause() = 0;
+ virtual status_t isPlaying(bool* state) = 0;
+ virtual status_t seekTo(int msec) = 0;
+ virtual status_t getCurrentPosition(int* msec) = 0;
+ virtual status_t getDuration(int* msec) = 0;
+ virtual status_t reset() = 0;
+ virtual status_t setAudioStreamType(int type) = 0;
+ virtual status_t setLooping(int loop) = 0;
+ virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaPlayer: public BnInterface<IMediaPlayer>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIAPLAYER_H
+
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
new file mode 100644
index 0000000..5d32811
--- /dev/null
+++ b/include/media/IMediaPlayerClient.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 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_IMEDIAPLAYERCLIENT_H
+#define ANDROID_IMEDIAPLAYERCLIENT_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+namespace android {
+
+class IMediaPlayerClient: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaPlayerClient);
+
+ virtual void notify(int msg, int ext1, int ext2) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaPlayerClient: public BnInterface<IMediaPlayerClient>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIAPLAYERCLIENT_H
+
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
new file mode 100644
index 0000000..8125cc9
--- /dev/null
+++ b/include/media/IMediaPlayerService.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 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_IMEDIAPLAYERSERVICE_H
+#define ANDROID_IMEDIAPLAYERSERVICE_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaPlayer.h>
+#include <media/IMediaMetadataRetriever.h>
+
+namespace android {
+
+class IMediaRecorder;
+
+class IMediaPlayerService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaPlayerService);
+
+ virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
+ virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
+
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
+ virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+ virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIAPLAYERSERVICE_H
+
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
new file mode 100644
index 0000000..eace996
--- /dev/null
+++ b/include/media/IMediaRecorder.h
@@ -0,0 +1,70 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_IMEDIARECORDER_H
+#define ANDROID_IMEDIARECORDER_H
+
+#include <utils/IInterface.h>
+
+namespace android {
+
+class ISurface;
+class ICamera;
+class IMediaPlayerClient;
+
+class IMediaRecorder: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaRecorder);
+
+ virtual status_t setCamera(const sp<ICamera>& camera) = 0;
+ virtual status_t setPreviewSurface(const sp<ISurface>& surface) = 0;
+ virtual status_t setVideoSource(int vs) = 0;
+ virtual status_t setAudioSource(int as) = 0;
+ virtual status_t setOutputFormat(int of) = 0;
+ virtual status_t setVideoEncoder(int ve) = 0;
+ virtual status_t setAudioEncoder(int ae) = 0;
+ virtual status_t setOutputFile(const char* path) = 0;
+ virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setVideoSize(int width, int height) = 0;
+ virtual status_t setVideoFrameRate(int frames_per_second) = 0;
+ virtual status_t setListener(const sp<IMediaPlayerClient>& listener) = 0;
+ virtual status_t prepare() = 0;
+ virtual status_t getMaxAmplitude(int* max) = 0;
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t reset() = 0;
+ virtual status_t init() = 0;
+ virtual status_t close() = 0;
+ virtual status_t release() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaRecorder: public BnInterface<IMediaRecorder>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIARECORDER_H
+
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
new file mode 100644
index 0000000..16764a9
--- /dev/null
+++ b/include/media/JetPlayer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 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 JETPLAYER_H_
+#define JETPLAYER_H_
+
+#include <utils/threads.h>
+#include <nativehelper/jni.h>
+
+#include <libsonivox/jet.h>
+#include <libsonivox/eas_types.h>
+#include "AudioTrack.h"
+
+
+namespace android {
+
+typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
+
+class JetPlayer {
+
+public:
+
+ // 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,
+ int trackBufferSize = 1200);
+ ~JetPlayer();
+ int init();
+ int release();
+
+ int loadFromFile(const char* url);
+ int loadFromFD(const int fd, const long long offset, const long long length);
+ int closeFile();
+ int play();
+ int pause();
+ int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID);
+ 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);
+
+ int getMaxTracks() { return mMaxTracks; };
+
+
+private:
+ static int renderThread(void*);
+ int render();
+ void fireUpdateOnStatusChange();
+ void fireEventsFromJetQueue();
+
+ JetPlayer() {} // no default constructor
+ void dump();
+ void dumpJetStatus(S_JET_STATUS* pJetStatus);
+
+ jetevent_callback mEventCallback;
+
+ jobject mJavaJetPlayerRef;
+ Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
+ pid_t mTid;
+ Condition mCondition;
+ volatile bool mRender;
+ bool mPaused;
+
+ EAS_STATE mState;
+ int* mMemFailedVar;
+
+ int mMaxTracks; // max number of MIDI tracks, usually 32
+ EAS_DATA_HANDLE mEasData;
+ EAS_FILE_LOCATOR mEasJetFileLoc;
+ EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
+ AudioTrack* mAudioTrack; // and we play it in this audio track
+ int mTrackBufferSize;
+ S_JET_STATUS mJetStatus;
+ S_JET_STATUS mPreviousJetStatus;
+
+ char mJetFilePath[256];
+
+
+}; // end class JetPlayer
+
+} // end namespace android
+
+
+
+#endif /*JETPLAYER_H_*/
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
new file mode 100644
index 0000000..b178836
--- /dev/null
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -0,0 +1,52 @@
+/*
+**
+** Copyright (C) 2008 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_MEDIAMETADATARETRIEVERINTERFACE_H
+#define ANDROID_MEDIAMETADATARETRIEVERINTERFACE_H
+
+#include <utils/RefBase.h>
+#include <media/mediametadataretriever.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+// Abstract base class
+class MediaMetadataRetrieverBase : public RefBase
+{
+public:
+ MediaMetadataRetrieverBase() {}
+ virtual ~MediaMetadataRetrieverBase() {}
+ virtual status_t setDataSource(const char *url) = 0;
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setMode(int mode) = 0;
+ virtual status_t getMode(int* mode) const = 0;
+ virtual VideoFrame* captureFrame() = 0;
+ virtual MediaAlbumArt* extractAlbumArt() = 0;
+ virtual const char* extractMetadata(int keyCode) = 0;
+};
+
+// MediaMetadataRetrieverInterface
+class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
+{
+public:
+ virtual ~MediaMetadataRetrieverInterface() {}
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAMETADATARETRIEVERINTERFACE_H
+
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
new file mode 100644
index 0000000..7f0e7b3
--- /dev/null
+++ b/include/media/MediaPlayerInterface.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 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_MEDIAPLAYERINTERFACE_H
+#define ANDROID_MEDIAPLAYERINTERFACE_H
+
+#ifdef __cplusplus
+
+#include <ui/ISurface.h>
+#include <utils/RefBase.h>
+
+#include <media/mediaplayer.h>
+#include <media/AudioSystem.h>
+
+namespace android {
+
+enum player_type {
+ PV_PLAYER = 1,
+ SONIVOX_PLAYER = 2,
+ VORBIS_PLAYER = 3
+};
+
+#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
+#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
+#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
+
+
+// callback mechanism for passing messages to MediaPlayer object
+typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
+
+// abstract base class - use MediaPlayerInterface
+class MediaPlayerBase : public RefBase
+{
+public:
+
+ // AudioSink: abstraction layer for audio output
+ class AudioSink : public RefBase {
+ public:
+ virtual ~AudioSink() {}
+ virtual bool ready() const = 0; // audio output is open and ready
+ virtual bool realtime() const = 0; // audio output is real-time output
+ virtual ssize_t bufferSize() const = 0;
+ virtual ssize_t frameCount() const = 0;
+ virtual ssize_t channelCount() const = 0;
+ virtual ssize_t frameSize() const = 0;
+ virtual uint32_t latency() const = 0;
+ virtual float msecsPerFrame() const = 0;
+ virtual status_t open(uint32_t sampleRate, int channelCount, int format=AudioSystem::PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
+ virtual void start() = 0;
+ virtual ssize_t write(const void* buffer, size_t size) = 0;
+ virtual void stop() = 0;
+ virtual void flush() = 0;
+ virtual void pause() = 0;
+ virtual void close() = 0;
+ };
+
+ MediaPlayerBase() : mCookie(0), mNotify(0) {}
+ virtual ~MediaPlayerBase() {}
+ virtual status_t initCheck() = 0;
+ virtual bool hardwareOutput() = 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<ISurface>& surface) = 0;
+ virtual status_t prepare() = 0;
+ virtual status_t prepareAsync() = 0;
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t pause() = 0;
+ virtual bool isPlaying() = 0;
+ virtual status_t seekTo(int msec) = 0;
+ virtual status_t getCurrentPosition(int *msec) = 0;
+ virtual status_t getDuration(int *msec) = 0;
+ virtual status_t reset() = 0;
+ virtual status_t setLooping(int loop) = 0;
+ virtual player_type playerType() = 0;
+ virtual void setNotifyCallback(void* cookie, notify_callback_f notifyFunc) {
+ mCookie = cookie; mNotify = notifyFunc; }
+
+protected:
+ virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
+
+ void* mCookie;
+ notify_callback_f mNotify;
+};
+
+// Implement this class for media players that use the AudioFlinger software mixer
+class MediaPlayerInterface : public MediaPlayerBase
+{
+public:
+ virtual ~MediaPlayerInterface() { }
+ virtual bool hardwareOutput() { return false; }
+ virtual void setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
+protected:
+ sp<AudioSink> mAudioSink;
+};
+
+// Implement this class for media players that output directo to hardware
+class MediaPlayerHWInterface : public MediaPlayerBase
+{
+public:
+ virtual ~MediaPlayerHWInterface() {}
+ virtual bool hardwareOutput() { return true; }
+ virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
+ virtual status_t setAudioStreamType(int streamType) = 0;
+};
+
+}; // namespace android
+
+#endif // __cplusplus
+
+
+#endif // ANDROID_MEDIAPLAYERINTERFACE_H
+
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
new file mode 100644
index 0000000..3315c59
--- /dev/null
+++ b/include/media/PVMediaRecorder.h
@@ -0,0 +1,65 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_PVMEDIARECORDER_H
+#define ANDROID_PVMEDIARECORDER_H
+
+#include <media/mediarecorder.h>
+#include <media/IMediaPlayerClient.h>
+
+namespace android {
+
+class ISurface;
+class ICamera;
+class AuthorDriverWrapper;
+
+class PVMediaRecorder
+{
+public:
+ PVMediaRecorder();
+ ~PVMediaRecorder();
+
+ status_t init();
+ status_t setAudioSource(audio_source as);
+ status_t setVideoSource(video_source vs);
+ status_t setOutputFormat(output_format of);
+ status_t setAudioEncoder(audio_encoder ae);
+ status_t setVideoEncoder(video_encoder ve);
+ status_t setVideoSize(int width, int height);
+ status_t setVideoFrameRate(int frames_per_second);
+ status_t setCamera(const sp<ICamera>& camera);
+ status_t setPreviewSurface(const sp<ISurface>& surface);
+ status_t setOutputFile(const char *path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ status_t setListener(const sp<IMediaPlayerClient>& listener);
+ status_t prepare();
+ status_t start();
+ status_t stop();
+ status_t close();
+ status_t reset();
+ status_t getMaxAmplitude(int *max);
+
+private:
+ status_t doStop();
+
+ AuthorDriverWrapper* mAuthorDriverWrapper;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PVMEDIARECORDER_H
+
diff --git a/include/media/PVMetadataRetriever.h b/include/media/PVMetadataRetriever.h
new file mode 100644
index 0000000..c202dfe
--- /dev/null
+++ b/include/media/PVMetadataRetriever.h
@@ -0,0 +1,51 @@
+/*
+**
+** Copyright (C) 2008 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_PVMETADATARETRIEVER_H
+#define ANDROID_PVMETADATARETRIEVER_H
+
+#include <utils/Errors.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+class MetadataDriver;
+
+class PVMetadataRetriever : public MediaMetadataRetrieverInterface
+{
+public:
+ PVMetadataRetriever();
+ virtual ~PVMetadataRetriever();
+
+ virtual status_t setDataSource(const char *url);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setMode(int mode);
+ virtual status_t getMode(int* mode) const;
+ virtual VideoFrame* captureFrame();
+ virtual MediaAlbumArt* extractAlbumArt();
+ virtual const char* extractMetadata(int keyCode);
+
+private:
+ mutable Mutex mLock;
+ MetadataDriver* mMetadataDriver;
+ char* mDataSourcePath;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PVMETADATARETRIEVER_H
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
new file mode 100644
index 0000000..6d98852
--- /dev/null
+++ b/include/media/PVPlayer.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 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_PVPLAYER_H
+#define ANDROID_PVPLAYER_H
+
+#include <utils/Errors.h>
+#include <media/MediaPlayerInterface.h>
+
+#define MAX_OPENCORE_INSTANCES 25
+
+#ifdef MAX_OPENCORE_INSTANCES
+#include <cutils/atomic.h>
+#endif
+
+class PlayerDriver;
+
+namespace android {
+
+class PVPlayer : public MediaPlayerInterface
+{
+public:
+ PVPlayer();
+ virtual ~PVPlayer();
+
+ virtual status_t initCheck();
+ 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<ISurface>& surface);
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int *msec);
+ virtual status_t getDuration(int *msec);
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType() { return PV_PLAYER; }
+
+ // make available to PlayerDriver
+ void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
+
+private:
+ static void do_nothing(status_t s, void *cookie, bool cancelled) { }
+ static void run_init(status_t s, void *cookie, bool cancelled);
+ static void run_set_video_surface(status_t s, void *cookie, bool cancelled);
+ static void run_set_audio_output(status_t s, void *cookie, bool cancelled);
+ static void run_prepare(status_t s, void *cookie, bool cancelled);
+
+ PlayerDriver* mPlayerDriver;
+ char * mDataSourcePath;
+ bool mIsDataSourceSet;
+ sp<ISurface> mSurface;
+ int mSharedFd;
+ status_t mInit;
+ int mDuration;
+
+#ifdef MAX_OPENCORE_INSTANCES
+ static volatile int32_t sNumInstances;
+#endif
+};
+
+}; // namespace android
+
+#endif // ANDROID_PVPLAYER_H
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
new file mode 100644
index 0000000..ec64e4d
--- /dev/null
+++ b/include/media/ToneGenerator.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2008 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_TONEGENERATOR_H_
+#define ANDROID_TONEGENERATOR_H_
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+
+namespace android {
+
+class ToneGenerator {
+public:
+
+ // List of all available tones
+ // This enum must be kept consistant with constants in ToneGenerator JAVA class
+ enum tone_type {
+ // DTMF tones ITU-T Recommendation Q.23
+ TONE_DTMF_0 = 0, // 0 key: 1336Hz, 941Hz
+ TONE_DTMF_1, // 1 key: 1209Hz, 697Hz
+ TONE_DTMF_2, // 2 key: 1336Hz, 697Hz
+ TONE_DTMF_3, // 3 key: 1477Hz, 697Hz
+ TONE_DTMF_4, // 4 key: 1209Hz, 770Hz
+ TONE_DTMF_5, // 5 key: 1336Hz, 770Hz
+ TONE_DTMF_6, // 6 key: 1477Hz, 770Hz
+ TONE_DTMF_7, // 7 key: 1209Hz, 852Hz
+ TONE_DTMF_8, // 8 key: 1336Hz, 852Hz
+ TONE_DTMF_9, // 9 key: 1477Hz, 852Hz
+ TONE_DTMF_S, // * key: 1209Hz, 941Hz
+ TONE_DTMF_P, // # key: 1477Hz, 941Hz
+ TONE_DTMF_A, // A key: 1633Hz, 697Hz
+ TONE_DTMF_B, // B key: 1633Hz, 770Hz
+ TONE_DTMF_C, // C key: 1633Hz, 852Hz
+ TONE_DTMF_D, // D key: 1633Hz, 941Hz
+ // Call supervisory tones: 3GPP TS 22.001 (CEPT)
+ TONE_SUP_DIAL, // Dial tone: 425Hz, continuous
+ TONE_SUP_BUSY, // Busy tone: 425Hz, 500ms ON, 500ms OFF...
+ TONE_SUP_CONGESTION, // Congestion tone: 425Hz, 200ms ON, 200ms OFF...
+ TONE_SUP_RADIO_ACK, // Radio path acknowlegment: 425Hz, 200ms ON
+ TONE_SUP_RADIO_NOTAVAIL, // Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts
+ TONE_SUP_ERROR, // Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF...
+ TONE_SUP_CALL_WAITING, // Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+ TONE_SUP_RINGTONE, // Ring Tone: 425Hz, 1s ON, 4s OFF...
+ // Proprietary tones: 3GPP TS 31.111
+ TONE_PROP_BEEP, // General beep: 400Hz+1200Hz, 35ms ON
+ TONE_PROP_ACK, // Positive Acknowlgement: 1200Hz, 100ms ON, 100ms OFF 2 bursts
+ TONE_PROP_NACK, // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
+ TONE_PROP_PROMPT, // Prompt tone: 400Hz+1200Hz, 200ms ON
+ TONE_PROP_BEEP2, // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on
+ NUM_TONES
+ };
+
+ ToneGenerator(int streamType, float volume);
+ ~ToneGenerator();
+
+ bool startTone(int toneType);
+ void stopTone();
+
+ bool isInited() { return (mState == TONE_IDLE)?false:true;}
+
+private:
+
+ enum tone_state {
+ TONE_IDLE, // ToneGenerator is being initialized or initialization failed
+ TONE_INIT, // ToneGenerator has been successfully initialized and is not playing
+ TONE_STARTING, // ToneGenerator is starting playing
+ TONE_PLAYING, // ToneGenerator is playing
+ TONE_STOPPING, // ToneGenerator is stoping
+ TONE_RESTARTING //
+ };
+
+ 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
+ static const float TONEGEN_GAIN = 0.9; // Default gain passed to WaveGenerator().
+
+ // ToneDescriptor class contains all parameters needed to generate a tone:
+ // - The array waveFreq[] contains the frequencies of all individual waves making the multi-tone.
+ // The number of sine waves varies from 1 to TONEGEN_MAX_WAVES.
+ // The first null value indicates that no more waves are needed.
+ // - The array segments[] is used to generate the tone pulses. A segment is a period of time
+ // during which the tone is ON or OFF. Segments with even index (starting from 0)
+ // correspond to tone ON state and segments with odd index to OFF state.
+ // The data stored in segments[] is the duration of the corresponding period in ms.
+ // The first segment encountered with a 0 duration indicates that no more segment follows.
+ // - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated.
+ // When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
+ // If mCurCount > repeatCnt, the tone is stopped automatically.
+
+ class ToneDescriptor {
+ public:
+ unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
+ unsigned long segments[TONEGEN_MAX_SEGMENTS+1];
+ unsigned long repeatCnt;
+ };
+
+ static const ToneDescriptor toneDescriptors[NUM_TONES];
+
+ unsigned int mTotalSmp; // Total number of audio samples played (gives current time)
+ unsigned int mNextSegSmp; // Position of next segment transition expressed in samples
+ // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
+ // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
+ // no crash will occur but tone sequence will show a glitch.
+
+ unsigned short mCurSegment; // Current segment index in ToneDescriptor segments[]
+ unsigned short mCurCount; // Current sequence repeat count
+ volatile unsigned short mState; // ToneGenerator state (tone_state)
+ const ToneDescriptor *mpToneDesc; // pointer to active tone descriptor
+ const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor
+
+ int mSamplingRate; // AudioFlinger Sampling rate
+ 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
+ Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
+ float mVolume; // Volume applied to audio track
+ int mStreamType; // Audio stream used for output
+ unsigned int mProcessSize; // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
+
+ bool initAudioTrack();
+ static void audioCallback(int event, void* user, void *info);
+ bool prepareWave();
+ unsigned int numWaves();
+ void clearWaveGens();
+
+ // WaveGenerator generates a single sine wave
+ class WaveGenerator {
+ public:
+ enum gen_command {
+ WAVEGEN_START, // Start/restart wave from phase 0
+ WAVEGEN_CONT, // Continue wave from current phase
+ WAVEGEN_STOP // Stop wave on zero crossing
+ };
+
+ WaveGenerator(unsigned short samplingRate, unsigned short frequency,
+ float volume);
+ ~WaveGenerator();
+
+ void getSamples(short *outBuffer, unsigned int count,
+ unsigned int command);
+
+ private:
+ static const short GEN_AMP = 32000; // amplitude of generator
+ static const short S_Q14 = 14; // shift for Q14
+ static const short S_Q15 = 15; // shift for Q15
+
+ short mA1_Q14; // Q14 coefficient
+ // delay line of full amplitude generator
+ short mS1, mS2; // delay line S2 oldest
+ short mS2_0; // saved value for reinitialisation
+ short mAmplitude_Q15; // Q15 amplitude
+ };
+
+ Vector<WaveGenerator *> mWaveGens; // list of active wave generators.
+};
+
+}
+; // namespace android
+
+#endif /*ANDROID_TONEGENERATOR_H_*/
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
new file mode 100644
index 0000000..f2719d3
--- /dev/null
+++ b/include/media/mediametadataretriever.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 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 MEDIAMETADATARETRIEVER_H
+#define MEDIAMETADATARETRIEVER_H
+
+#include <utils/Errors.h> // for status_t
+#include <utils/threads.h>
+#include <utils/IMemory.h>
+#include <media/IMediaMetadataRetriever.h>
+
+namespace android {
+
+class IMediaPlayerService;
+class IMediaMetadataRetriever;
+
+// Keep these in synch with the constants defined in MediaMetadataRetriever.java
+// class.
+enum {
+ METADATA_KEY_CD_TRACK_NUMBER = 0,
+ METADATA_KEY_ALBUM = 1,
+ METADATA_KEY_ARTIST = 2,
+ METADATA_KEY_AUTHOR = 3,
+ METADATA_KEY_COMPOSER = 4,
+ METADATA_KEY_DATE = 5,
+ METADATA_KEY_GENRE = 6,
+ METADATA_KEY_TITLE = 7,
+ METADATA_KEY_YEAR = 8,
+ METADATA_KEY_DURATION = 9,
+ METADATA_KEY_NUM_TRACKS = 10,
+ METADATA_KEY_IS_DRM_CRIPPLED = 11,
+ METADATA_KEY_CODEC = 12,
+ METADATA_KEY_RATING = 13,
+ METADATA_KEY_COMMENT = 14,
+ METADATA_KEY_COPYRIGHT = 15,
+ METADATA_KEY_BIT_RATE = 16,
+ METADATA_KEY_FRAME_RATE = 17,
+ METADATA_KEY_VIDEO_FORMAT = 18,
+ METADATA_KEY_VIDEO_HEIGHT = 19,
+ METADATA_KEY_VIDEO_WIDTH = 20,
+ // Add more here...
+};
+
+
+class MediaMetadataRetriever: public RefBase
+{
+public:
+ MediaMetadataRetriever();
+ ~MediaMetadataRetriever();
+ void disconnect();
+ status_t setDataSource(const char* dataSourceUrl);
+ status_t setDataSource(int fd, int64_t offset, int64_t length);
+ status_t setMode(int mode);
+ status_t getMode(int* mode);
+ sp<IMemory> captureFrame();
+ sp<IMemory> extractAlbumArt();
+ const char* extractMetadata(int keyCode);
+
+private:
+ static const sp<IMediaPlayerService>& getService();
+
+ class DeathNotifier: public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {}
+ virtual ~DeathNotifier();
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
+ static sp<DeathNotifier> sDeathNotifier;
+ static Mutex sServiceLock;
+ static sp<IMediaPlayerService> sService;
+
+ Mutex mLock;
+ sp<IMediaMetadataRetriever> mRetriever;
+
+};
+
+}; // namespace android
+
+#endif // MEDIAMETADATARETRIEVER_H
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
new file mode 100644
index 0000000..7288445
--- /dev/null
+++ b/include/media/mediaplayer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2007 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_MEDIAPLAYER_H
+#define ANDROID_MEDIAPLAYER_H
+
+#include <utils/IMemory.h>
+#include <ui/Surface.h>
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaPlayer.h>
+#include <media/IMediaPlayerService.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+enum media_event_type {
+ MEDIA_NOP = 0, // interface test message
+ MEDIA_PREPARED = 1,
+ MEDIA_PLAYBACK_COMPLETE = 2,
+ MEDIA_BUFFERING_UPDATE = 3,
+ MEDIA_SEEK_COMPLETE = 4,
+ MEDIA_SET_VIDEO_SIZE = 5,
+ MEDIA_ERROR = 100,
+};
+
+typedef int media_error_type;
+const media_error_type MEDIA_ERROR_UNKNOWN = 1;
+const media_error_type MEDIA_ERROR_SERVER_DIED = 100;
+
+enum media_player_states {
+ MEDIA_PLAYER_STATE_ERROR = 0,
+ MEDIA_PLAYER_IDLE = 1 << 0,
+ MEDIA_PLAYER_INITIALIZED = 1 << 1,
+ MEDIA_PLAYER_PREPARING = 1 << 2,
+ MEDIA_PLAYER_PREPARED = 1 << 3,
+ MEDIA_PLAYER_STARTED = 1 << 4,
+ MEDIA_PLAYER_PAUSED = 1 << 5,
+ MEDIA_PLAYER_STOPPED = 1 << 6,
+ MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
+};
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class MediaPlayerListener: virtual public RefBase
+{
+public:
+ virtual void notify(int msg, int ext1, int ext2) = 0;
+};
+
+class MediaPlayer : public BnMediaPlayerClient
+{
+public:
+ MediaPlayer();
+ ~MediaPlayer();
+ void onFirstRef();
+ void disconnect();
+ status_t setDataSource(const char *url);
+ status_t setDataSource(int fd, int64_t offset, int64_t length);
+ status_t setVideoSurface(const sp<Surface>& surface);
+ status_t setListener(const sp<MediaPlayerListener>& listener);
+ status_t prepare();
+ status_t prepareAsync();
+ status_t start();
+ status_t stop();
+ status_t pause();
+ bool isPlaying();
+ status_t getVideoWidth(int *w);
+ status_t getVideoHeight(int *h);
+ status_t seekTo(int msec);
+ status_t getCurrentPosition(int *msec);
+ status_t getDuration(int *msec);
+ status_t reset();
+ status_t setAudioStreamType(int type);
+ status_t setLooping(int loop);
+ bool isLooping();
+ status_t setVolume(float leftVolume, float rightVolume);
+ void notify(int msg, int ext1, int ext2);
+ static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+ static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+
+private:
+ void clear_l();
+ status_t seekTo_l(int msec);
+ status_t prepareAsync_l();
+ status_t getDuration_l(int *msec);
+ status_t setDataSource(const sp<IMediaPlayer>& player);
+
+ static const sp<IMediaPlayerService>& getMediaPlayerService();
+ static void addObitRecipient(const wp<MediaPlayer>& recipient);
+ static void removeObitRecipient(const wp<MediaPlayer>& recipient);
+
+ class DeathNotifier: public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {}
+ virtual ~DeathNotifier();
+
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
+ sp<IMediaPlayer> mPlayer;
+ Mutex mLock;
+ Mutex mNotifyLock;
+ Condition mSignal;
+ sp<MediaPlayerListener> mListener;
+ void* mCookie;
+ media_player_states mCurrentState;
+ int mDuration;
+ int mCurrentPosition;
+ int mSeekPosition;
+ bool mPrepareSync;
+ status_t mPrepareStatus;
+ int mStreamType;
+ bool mLoop;
+ float mLeftVolume;
+ float mRightVolume;
+ int mVideoWidth;
+ int mVideoHeight;
+
+ friend class DeathNotifier;
+
+ static Mutex sServiceLock;
+ static sp<IMediaPlayerService> sMediaPlayerService;
+ static sp<DeathNotifier> sDeathNotifier;
+ static SortedVector< wp<MediaPlayer> > sObitRecipients;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYER_H
+
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
new file mode 100644
index 0000000..8991f08
--- /dev/null
+++ b/include/media/mediarecorder.h
@@ -0,0 +1,155 @@
+/*
+ ** Copyright (C) 2008 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_MEDIARECORDER_H
+#define ANDROID_MEDIARECORDER_H
+
+#include <utils.h>
+#include <media/IMediaPlayerClient.h>
+
+namespace android {
+
+class Surface;
+class IMediaRecorder;
+class ICamera;
+
+typedef void (*media_completion_f)(status_t status, void *cookie);
+
+/* Do not change these values without updating their counterparts
+ * in java/android/android/media/MediaRecorder.java!
+ */
+enum audio_source {
+ AUDIO_SOURCE_DEFAULT = 0,
+ AUDIO_SOURCE_MIC = 1,
+};
+
+enum video_source {
+ VIDEO_SOURCE_DEFAULT = 0,
+ VIDEO_SOURCE_CAMERA = 1,
+};
+
+//Please update java/android/android/media/MediaRecorder.java if the following is updated.
+enum output_format {
+ OUTPUT_FORMAT_DEFAULT = 0,
+ OUTPUT_FORMAT_THREE_GPP,
+ OUTPUT_FORMAT_MPEG_4,
+ OUTPUT_FORMAT_RAW_AMR,
+ OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
+};
+
+enum audio_encoder {
+ AUDIO_ENCODER_DEFAULT = 0,
+ AUDIO_ENCODER_AMR_NB = 1,
+};
+
+enum video_encoder {
+ VIDEO_ENCODER_DEFAULT = 0,
+ VIDEO_ENCODER_H263 = 1,
+ VIDEO_ENCODER_H264 = 2,
+ VIDEO_ENCODER_MPEG_4_SP = 3,
+};
+
+// Maximum frames per second is 24
+#define MEDIA_RECORDER_MAX_FRAME_RATE 24
+
+/*
+ * The state machine of the media_recorder uses a set of different state names.
+ * The mapping between the media_recorder and the pvauthorengine is shown below:
+ *
+ * mediarecorder pvauthorengine
+ * ----------------------------------------------------------------
+ * MEDIA_RECORDER_ERROR ERROR
+ * MEDIA_RECORDER_IDLE IDLE
+ * MEDIA_RECORDER_INITIALIZED OPENED
+ * MEDIA_RECORDER_DATASOURCE_CONFIGURED
+ * MEDIA_RECORDER_PREPARED INITIALIZED
+ * MEDIA_RECORDER_RECORDING RECORDING
+ */
+enum media_recorder_states {
+ MEDIA_RECORDER_ERROR = 0,
+ MEDIA_RECORDER_IDLE = 1 << 0,
+ MEDIA_RECORDER_INITIALIZED = 1 << 1,
+ MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2,
+ MEDIA_RECORDER_PREPARED = 1 << 3,
+ MEDIA_RECORDER_RECORDING = 1 << 4,
+};
+
+// The "msg" code passed to the listener in notify.
+enum {
+ MEDIA_RECORDER_EVENT_ERROR = 1
+};
+
+enum {
+ MEDIA_RECORDER_ERROR_UNKNOWN = 1
+};
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class MediaRecorderListener: virtual public RefBase
+{
+public:
+ virtual void notify(int msg, int ext1, int ext2) = 0;
+};
+
+class MediaRecorder : public BnMediaPlayerClient
+{
+public:
+ MediaRecorder();
+ ~MediaRecorder();
+
+ status_t initCheck();
+ status_t setCamera(const sp<ICamera>& camera);
+ status_t setPreviewSurface(const sp<Surface>& surface);
+ status_t setVideoSource(int vs);
+ status_t setAudioSource(int as);
+ status_t setOutputFormat(int of);
+ status_t setVideoEncoder(int ve);
+ status_t setAudioEncoder(int ae);
+ status_t setOutputFile(const char* path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ status_t setVideoSize(int width, int height);
+ status_t setVideoFrameRate(int frames_per_second);
+ status_t setListener(const sp<MediaRecorderListener>& listener);
+ status_t prepare();
+ status_t getMaxAmplitude(int* max);
+ status_t start();
+ status_t stop();
+ status_t reset();
+ status_t init();
+ status_t close();
+ status_t release();
+ void notify(int msg, int ext1, int ext2);
+
+private:
+ void doCleanUp();
+ status_t doReset();
+
+ sp<IMediaRecorder> mMediaRecorder;
+ sp<MediaRecorderListener> mListener;
+ media_recorder_states mCurrentState;
+ bool mIsAudioSourceSet;
+ bool mIsVideoSourceSet;
+ bool mIsAudioEncoderSet;
+ bool mIsVideoEncoderSet;
+ bool mIsOutputFileSet;
+ Mutex mLock;
+ Mutex mNotifyLock;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIARECORDER_H
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
new file mode 100644
index 0000000..fbef1db
--- /dev/null
+++ b/include/media/mediascanner.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 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 MEDIASCANNER_H
+#define MEDIASCANNER_H
+
+#include <utils.h>
+#include <pthread.h>
+
+namespace android {
+
+class MediaScannerClient;
+class StringArray;
+
+class MediaScanner
+{
+public:
+ MediaScanner();
+ ~MediaScanner();
+
+ typedef bool (*ExceptionCheck)(void* env);
+
+ status_t processFile(const char *path, const char *mimeType, MediaScannerClient& client);
+ status_t processDirectory(const char *path, const char* extensions,
+ MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv);
+ void setLocale(const char* locale);
+
+ // extracts album art as a block of data
+ char* extractAlbumArt(int fd);
+
+ static void uninitializeForThread();
+
+private:
+ status_t doProcessDirectory(char *path, int pathRemaining, const char* extensions,
+ MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv);
+ void initializeForThread();
+
+ // current locale (like "ja_JP"), created/destroyed with strdup()/free()
+ char* mLocale;
+};
+
+
+class MediaScannerClient
+{
+public:
+ MediaScannerClient();
+ virtual ~MediaScannerClient();
+ void setLocale(const char* locale);
+ void beginFile();
+ bool addStringTag(const char* name, const char* value);
+ void endFile();
+
+ virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
+ virtual bool handleStringTag(const char* name, const char* value) = 0;
+ virtual bool setMimeType(const char* mimeType) = 0;
+
+protected:
+ void convertValues(uint32_t encoding);
+
+protected:
+ // cached name and value strings, for native encoding support.
+ StringArray* mNames;
+ StringArray* mValues;
+
+ // default encoding based on MediaScanner::mLocale string
+ uint32_t mLocaleEncoding;
+};
+
+}; // namespace android
+
+#endif // MEDIASCANNER_H
+
diff --git a/include/media/thread_init.h b/include/media/thread_init.h
new file mode 100644
index 0000000..2c0c1f1
--- /dev/null
+++ b/include/media/thread_init.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 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 THREAD_INIT_H
+#define THREAD_INIT_H
+
+bool InitializeForThread();
+void UninitializeForThread();
+void keydestructor(void*);
+
+#endif /* THREAD_INIT_H*/
+
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
new file mode 100644
index 0000000..1991aa7
--- /dev/null
+++ b/include/private/media/AudioTrackShared.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 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_AUDIO_TRACK_SHARED_H
+#define ANDROID_AUDIO_TRACK_SHARED_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define MAX_SAMPLE_RATE 65535
+#define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
+// Maximum cumulated timeout milliseconds before restarting audioflinger thread
+#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
+#define MAX_RUN_TIMEOUT_MS 1000
+#define WAIT_PERIOD_MS 10
+
+
+struct audio_track_cblk_t
+{
+
+ // The data members are grouped so that members accessed frequently and in the same context
+ // are in the same line of data cache.
+ Mutex lock;
+ Condition cv;
+ volatile uint32_t user;
+ volatile uint32_t server;
+ uint32_t userBase;
+ uint32_t serverBase;
+ void* buffers;
+ uint32_t frameCount;
+ // Cache line boundary
+ uint32_t loopStart;
+ uint32_t loopEnd;
+ int loopCount;
+ volatile union {
+ uint16_t volume[2];
+ uint32_t volumeLR;
+ };
+ uint16_t sampleRate;
+ uint16_t channels;
+ int16_t flowControlFlag; // underrun (out) or overrrun (in) indication
+ uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
+ uint8_t forceReady;
+ uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
+ uint16_t waitTimeMs; // Cumulated wait time
+ // Padding ensuring that data buffer starts on a cache line boundary (32 bytes).
+ // See AudioFlinger::TrackBase constructor
+ int32_t Padding[3];
+
+ audio_track_cblk_t();
+ uint32_t stepUser(uint32_t frameCount);
+ bool stepServer(uint32_t frameCount);
+ void* buffer(uint32_t offset) const;
+ uint32_t framesAvailable();
+ uint32_t framesAvailable_l();
+ uint32_t framesReady();
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_TRACK_SHARED_H
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
new file mode 100644
index 0000000..9c35274
--- /dev/null
+++ b/include/private/media/VideoFrame.h
@@ -0,0 +1,127 @@
+/*
+**
+** Copyright (C) 2008 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_VIDEO_FRAME_H
+#define ANDROID_VIDEO_FRAME_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// A simple buffer to hold binary data
+class MediaAlbumArt
+{
+public:
+ MediaAlbumArt(): mSize(0), mData(0) {}
+
+ explicit MediaAlbumArt(const char* url) {
+ mSize = 0;
+ mData = NULL;
+ FILE *in = fopen(url, "r");
+ if (!in) {
+ return;
+ }
+ fseek(in, 0, SEEK_END);
+ mSize = ftell(in); // Allocating buffer of size equals to the external file size.
+ if (mSize == 0 || (mData = new uint8_t[mSize]) == NULL) {
+ fclose(in);
+ if (mSize != 0) {
+ mSize = 0;
+ }
+ return;
+ }
+ rewind(in);
+ if (fread(mData, 1, mSize, in) != mSize) { // Read failed.
+ delete[] mData;
+ mData = NULL;
+ mSize = 0;
+ return;
+ }
+ fclose(in);
+ }
+
+ MediaAlbumArt(const MediaAlbumArt& copy) {
+ mSize = copy.mSize;
+ mData = NULL; // initialize it first
+ if (mSize > 0 && copy.mData != NULL) {
+ mData = new uint8_t[copy.mSize];
+ if (mData != NULL) {
+ memcpy(mData, copy.mData, mSize);
+ } else {
+ mSize = 0;
+ }
+ }
+ }
+
+ ~MediaAlbumArt() {
+ if (mData != 0) {
+ delete[] mData;
+ }
+ }
+
+ // Intentional public access modifier:
+ // We have to know the internal structure in order to share it between
+ // processes?
+ uint32_t mSize; // Number of bytes in mData
+ uint8_t* mData; // Actual binary data
+};
+
+// Represents a color converted (RGB-based) video frame
+// with bitmap pixels stored in FrameBuffer
+class VideoFrame
+{
+public:
+ VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0), mData(0) {}
+
+ VideoFrame(const VideoFrame& copy) {
+ mWidth = copy.mWidth;
+ mHeight = copy.mHeight;
+ mDisplayWidth = copy.mDisplayWidth;
+ mDisplayHeight = copy.mDisplayHeight;
+ mSize = copy.mSize;
+ mData = NULL; // initialize it first
+ if (mSize > 0 && copy.mData != NULL) {
+ mData = new uint8_t[mSize];
+ if (mData != NULL) {
+ memcpy(mData, copy.mData, mSize);
+ } else {
+ mSize = 0;
+ }
+ }
+ }
+
+ ~VideoFrame() {
+ if (mData != 0) {
+ delete[] mData;
+ }
+ }
+
+ // Intentional public access modifier:
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+ uint32_t mSize; // Number of bytes in mData
+ uint8_t* mData; // Actual binary data
+};
+
+}; // namespace android
+
+#endif // ANDROID_VIDEO_FRAME_H
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
new file mode 100644
index 0000000..0c7ad46
--- /dev/null
+++ b/include/private/opengles/gl_context.h
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2006 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_OPENGLES_CONTEXT_H
+#define ANDROID_OPENGLES_CONTEXT_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <pthread.h>
+#ifdef HAVE_ANDROID_OS
+#include <bionic_tls.h>
+#endif
+
+#include <private/pixelflinger/ggl_context.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+namespace android {
+
+const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10;
+
+class EGLTextureObject;
+class EGLSurfaceManager;
+class EGLBufferObjectManager;
+
+namespace gl {
+
+struct ogles_context_t;
+struct matrixx_t;
+struct transform_t;
+struct buffer_t;
+
+ogles_context_t* getGlContext();
+
+template<typename T>
+static inline void swap(T& a, T& b) {
+ T t(a); a = b; b = t;
+}
+template<typename T>
+inline T max(T a, T b) {
+ return a<b ? b : a;
+}
+template<typename T>
+inline T max(T a, T b, T c) {
+ return max(a, max(b, c));
+}
+template<typename T>
+inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+template<typename T>
+inline T min(T a, T b, T c) {
+ return min(a, min(b, c));
+}
+template<typename T>
+inline T min(T a, T b, T c, T d) {
+ return min(min(a,b), min(c,d));
+}
+
+// ----------------------------------------------------------------------------
+// vertices
+// ----------------------------------------------------------------------------
+
+struct vec3_t {
+ union {
+ struct { GLfixed x, y, z; };
+ struct { GLfixed r, g, b; };
+ struct { GLfixed S, T, R; };
+ GLfixed v[3];
+ };
+};
+
+struct vec4_t {
+ union {
+ struct { GLfixed x, y, z, w; };
+ struct { GLfixed r, g, b, a; };
+ struct { GLfixed S, T, R, Q; };
+ GLfixed v[4];
+ };
+};
+
+struct vertex_t {
+ enum {
+ // these constant matter for our clipping
+ CLIP_L = 0x0001, // clipping flags
+ CLIP_R = 0x0002,
+ CLIP_B = 0x0004,
+ CLIP_T = 0x0008,
+ CLIP_N = 0x0010,
+ CLIP_F = 0x0020,
+
+ EYE = 0x0040,
+ RESERVED = 0x0080,
+
+ USER_CLIP_0 = 0x0100, // user clipping flags
+ USER_CLIP_1 = 0x0200,
+ USER_CLIP_2 = 0x0400,
+ USER_CLIP_3 = 0x0800,
+ USER_CLIP_4 = 0x1000,
+ USER_CLIP_5 = 0x2000,
+
+ LIT = 0x4000, // lighting has been applied
+ TT = 0x8000, // texture coords transformed
+
+ FRUSTUM_CLIP_ALL= 0x003F,
+ USER_CLIP_ALL = 0x3F00,
+ CLIP_ALL = 0x3F3F,
+ };
+
+ // the fields below are arranged to minimize d-cache usage
+ // we group together, by cache-line, the fields most likely to be used
+
+ union {
+ vec4_t obj;
+ vec4_t eye;
+ };
+ vec4_t clip;
+
+ uint32_t flags;
+ size_t index; // cache tag, and vertex index
+ GLfixed fog;
+ uint8_t locked;
+ uint8_t mru;
+ uint8_t reserved[2];
+ vec4_t window;
+
+ vec4_t color;
+ vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
+ uint32_t reserved1[4];
+
+ inline void clear() {
+ flags = index = locked = mru = 0;
+ }
+};
+
+struct point_size_t {
+ GGLcoord size;
+ GLboolean smooth;
+};
+
+struct line_width_t {
+ GGLcoord width;
+ GLboolean smooth;
+};
+
+struct polygon_offset_t {
+ GLfixed factor;
+ GLfixed units;
+ GLboolean enable;
+};
+
+// ----------------------------------------------------------------------------
+// arrays
+// ----------------------------------------------------------------------------
+
+struct array_t {
+ typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*);
+ fetcher_t fetch;
+ GLvoid const* physical_pointer;
+ GLint size;
+ GLsizei stride;
+ GLvoid const* pointer;
+ buffer_t const* bo;
+ uint16_t type;
+ GLboolean enable;
+ GLboolean pad;
+ GLsizei bounds;
+ void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei);
+ inline void resolve();
+ inline const GLubyte* element(GLint i) const {
+ return (const GLubyte*)physical_pointer + i * stride;
+ }
+};
+
+struct array_machine_t {
+ array_t vertex;
+ array_t normal;
+ array_t color;
+ array_t texture[GGL_TEXTURE_UNIT_COUNT];
+ uint8_t activeTexture;
+ uint8_t tmu;
+ uint16_t cull;
+ uint32_t flags;
+ GLenum indicesType;
+ buffer_t const* array_buffer;
+ buffer_t const* element_array_buffer;
+
+ void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
+ void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
+
+ void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*);
+ void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*);
+ void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*);
+ void (*perspective)(ogles_context_t*c, vertex_t* v);
+ void (*clipVertex)(ogles_context_t* c, vertex_t* nv,
+ GGLfixed t, const vertex_t* s, const vertex_t* p);
+ void (*clipEye)(ogles_context_t* c, vertex_t* nv,
+ GGLfixed t, const vertex_t* s, const vertex_t* p);
+};
+
+struct vertex_cache_t {
+ enum {
+ // must be at least 4
+ // 3 vertice for triangles
+ // or 2 + 2 for indexed triangles w/ cache contention
+ VERTEX_BUFFER_SIZE = 8,
+ // must be a power of two and at least 3
+ VERTEX_CACHE_SIZE = 64, // 8 KB
+
+ INDEX_BITS = 16,
+ INDEX_MASK = ((1LU<<INDEX_BITS)-1),
+ INDEX_SEQ = 1LU<<INDEX_BITS,
+ };
+ vertex_t* vBuffer;
+ vertex_t* vCache;
+ uint32_t sequence;
+ void* base;
+ uint32_t total;
+ uint32_t misses;
+ int64_t startTime;
+ void init();
+ void uninit();
+ void clear();
+ void dump_stats(GLenum mode);
+};
+
+// ----------------------------------------------------------------------------
+// fog
+// ----------------------------------------------------------------------------
+
+struct fog_t {
+ GLfixed density;
+ GLfixed start;
+ GLfixed end;
+ GLfixed invEndMinusStart;
+ GLenum mode;
+ GLfixed (*fog)(ogles_context_t* c, GLfixed z);
+};
+
+// ----------------------------------------------------------------------------
+// user clip planes
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_CLIP_PLANES = 6;
+
+struct clip_plane_t {
+ vec4_t equation;
+};
+
+struct user_clip_planes_t {
+ clip_plane_t plane[OGLES_MAX_CLIP_PLANES];
+ uint32_t enable;
+};
+
+// ----------------------------------------------------------------------------
+// lighting
+// ----------------------------------------------------------------------------
+
+const unsigned int OGLES_MAX_LIGHTS = 8;
+
+struct light_t {
+ vec4_t ambient;
+ vec4_t diffuse;
+ vec4_t specular;
+ vec4_t implicitAmbient;
+ vec4_t implicitDiffuse;
+ vec4_t implicitSpecular;
+ vec4_t position; // position in eye space
+ vec4_t objPosition;
+ vec4_t normalizedObjPosition;
+ vec4_t spotDir;
+ vec4_t normalizedSpotDir;
+ GLfixed spotExp;
+ GLfixed spotCutoff;
+ GLfixed spotCutoffCosine;
+ GLfixed attenuation[3];
+ GLfixed rConstAttenuation;
+ GLboolean enable;
+};
+
+struct material_t {
+ vec4_t ambient;
+ vec4_t diffuse;
+ vec4_t specular;
+ vec4_t emission;
+ GLfixed shininess;
+};
+
+struct light_model_t {
+ vec4_t ambient;
+ GLboolean twoSide;
+};
+
+struct color_material_t {
+ GLenum face;
+ GLenum mode;
+ GLboolean enable;
+};
+
+struct lighting_t {
+ light_t lights[OGLES_MAX_LIGHTS];
+ material_t front;
+ light_model_t lightModel;
+ color_material_t colorMaterial;
+ uint32_t enabledLights;
+ GLboolean enable;
+ vec4_t implicitSceneEmissionAndAmbient;
+ GLenum shadeModel;
+ typedef void (*light_fct_t)(ogles_context_t*, vertex_t*);
+ void (*lightVertex)(ogles_context_t* c, vertex_t* v);
+ void (*lightTriangle)(ogles_context_t* c,
+ vertex_t* v0, vertex_t* v1, vertex_t* v2);
+};
+
+struct culling_t {
+ GLenum cullFace;
+ GLenum frontFace;
+ GLboolean enable;
+};
+
+// ----------------------------------------------------------------------------
+// textures
+// ----------------------------------------------------------------------------
+
+struct texture_unit_t {
+ GLuint name;
+ EGLTextureObject* texture;
+ uint8_t dirty;
+};
+
+struct texture_state_t
+{
+ texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
+ int active; // active tmu
+ EGLTextureObject* defaultTexture;
+ GGLContext* ggl;
+ uint8_t packAlignment;
+ uint8_t unpackAlignment;
+};
+
+// ----------------------------------------------------------------------------
+// transformation and matrices
+// ----------------------------------------------------------------------------
+
+struct matrixf_t;
+
+struct matrixx_t {
+ GLfixed m[16];
+ void load(const matrixf_t& rhs);
+};
+
+struct matrix_stack_t;
+
+
+struct matrixf_t {
+ void loadIdentity();
+ void load(const matrixf_t& rhs);
+
+ inline GLfloat* editElements() { return m; }
+ inline GLfloat const* elements() const { return m; }
+
+ void set(const GLfixed* rhs);
+ void set(const GLfloat* rhs);
+
+ static void multiply(matrixf_t& r,
+ const matrixf_t& lhs, const matrixf_t& rhs);
+
+ void dump(const char* what);
+
+private:
+ friend struct matrix_stack_t;
+ GLfloat m[16];
+ void load(const GLfixed* rhs);
+ void load(const GLfloat* rhs);
+ void multiply(const matrixf_t& rhs);
+ void translate(GLfloat x, GLfloat y, GLfloat z);
+ void scale(GLfloat x, GLfloat y, GLfloat z);
+ void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+};
+
+enum {
+ OP_IDENTITY = 0x00,
+ OP_TRANSLATE = 0x01,
+ OP_UNIFORM_SCALE = 0x02,
+ OP_SCALE = 0x05,
+ OP_ROTATE = 0x08,
+ OP_SKEW = 0x10,
+ OP_ALL = 0x1F
+};
+
+struct transform_t {
+ enum {
+ FLAGS_2D_PROJECTION = 0x1
+ };
+ matrixx_t matrix;
+ uint32_t flags;
+ uint32_t ops;
+
+ union {
+ struct {
+ void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
+ void (*point3)(transform_t const* t, vec4_t*, vec4_t const*);
+ void (*point4)(transform_t const* t, vec4_t*, vec4_t const*);
+ };
+ void (*pointv[3])(transform_t const* t, vec4_t*, vec4_t const*);
+ };
+
+ void loadIdentity();
+ void picker();
+ void dump(const char* what);
+};
+
+struct mvui_transform_t : public transform_t
+{
+ void picker();
+};
+
+struct matrix_stack_t {
+ enum {
+ DO_PICKER = 0x1,
+ DO_FLOAT_TO_FIXED = 0x2
+ };
+ transform_t transform;
+ uint8_t maxDepth;
+ uint8_t depth;
+ uint8_t dirty;
+ uint8_t reserved;
+ matrixf_t *stack;
+ uint8_t *ops;
+ void init(int depth);
+ void uninit();
+ void loadIdentity();
+ void load(const GLfixed* rhs);
+ void load(const GLfloat* rhs);
+ void multiply(const matrixf_t& rhs);
+ void translate(GLfloat x, GLfloat y, GLfloat z);
+ void scale(GLfloat x, GLfloat y, GLfloat z);
+ void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
+ GLint push();
+ GLint pop();
+ void validate();
+ matrixf_t& top() { return stack[depth]; }
+ const matrixf_t& top() const { return stack[depth]; }
+ const uint32_t top_ops() const { return ops[depth]; }
+ inline bool isRigidBody() const {
+ return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
+ }
+};
+
+struct vp_transform_t {
+ transform_t transform;
+ matrixf_t matrix;
+ GLfloat zNear;
+ GLfloat zFar;
+ void loadIdentity();
+};
+
+struct transform_state_t {
+ enum {
+ MODELVIEW = 0x01,
+ PROJECTION = 0x02,
+ VIEWPORT = 0x04,
+ TEXTURE = 0x08,
+ MVUI = 0x10,
+ MVIT = 0x20,
+ MVP = 0x40,
+ };
+ matrix_stack_t *current;
+ matrix_stack_t modelview;
+ matrix_stack_t projection;
+ matrix_stack_t texture[GGL_TEXTURE_UNIT_COUNT];
+
+ // modelview * projection
+ transform_t mvp __attribute__((aligned(32)));
+ // viewport transformation
+ vp_transform_t vpt __attribute__((aligned(32)));
+ // same for 4-D vertices
+ transform_t mvp4;
+ // full modelview inverse transpose
+ transform_t mvit4;
+ // upper 3x3 of mv-inverse-transpose (for normals)
+ mvui_transform_t mvui;
+
+ GLenum matrixMode;
+ GLenum rescaleNormals;
+ uint32_t dirty;
+ void invalidate();
+ void update_mvp();
+ void update_mvit();
+ void update_mvui();
+};
+
+struct viewport_t {
+ GLint x;
+ GLint y;
+ GLsizei w;
+ GLsizei h;
+ struct {
+ GLint x;
+ GLint y;
+ } surfaceport;
+ struct {
+ GLint x;
+ GLint y;
+ GLsizei w;
+ GLsizei h;
+ } scissor;
+};
+
+// ----------------------------------------------------------------------------
+// Lerping
+// ----------------------------------------------------------------------------
+
+struct compute_iterators_t
+{
+ void initTriangle(
+ vertex_t const* v0,
+ vertex_t const* v1,
+ vertex_t const* v2);
+
+ void initLine(
+ vertex_t const* v0,
+ vertex_t const* v1);
+
+ inline void initLerp(vertex_t const* v0, uint32_t enables);
+
+ int iteratorsScale(int32_t it[3],
+ int32_t c0, int32_t c1, int32_t c2) const;
+
+ void iterators1616(GGLfixed it[3],
+ GGLfixed c0, GGLfixed c1, GGLfixed c2) const;
+
+ void iterators0032(int32_t it[3],
+ int32_t c0, int32_t c1, int32_t c2) const;
+
+ void iterators0032(int64_t it[3],
+ int32_t c0, int32_t c1, int32_t c2) const;
+
+ GGLcoord area() const { return m_area; }
+
+private:
+ // don't change order of members here -- used by iterators.S
+ GGLcoord m_dx01, m_dy10, m_dx20, m_dy02;
+ GGLcoord m_x0, m_y0;
+ GGLcoord m_area;
+ uint8_t m_scale;
+ uint8_t m_area_scale;
+ uint8_t m_reserved[2];
+
+};
+
+// ----------------------------------------------------------------------------
+// state
+// ----------------------------------------------------------------------------
+
+#ifdef HAVE_ANDROID_OS
+ // We have a dedicated TLS slot in bionic
+ inline void setGlThreadSpecific(ogles_context_t *value) {
+ ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
+ }
+ inline ogles_context_t* getGlThreadSpecific() {
+ return (ogles_context_t *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
+ }
+#else
+ extern pthread_key_t gGLKey;
+ inline void setGlThreadSpecific(ogles_context_t *value) {
+ pthread_setspecific(gGLKey, value);
+ }
+ inline ogles_context_t* getGlThreadSpecific() {
+ return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey));
+ }
+#endif
+
+
+struct prims_t {
+ typedef ogles_context_t* GL;
+ void (*renderPoint)(GL, vertex_t*);
+ void (*renderLine)(GL, vertex_t*, vertex_t*);
+ void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
+};
+
+struct ogles_context_t {
+ context_t rasterizer;
+ array_machine_t arrays __attribute__((aligned(32)));
+ texture_state_t textures;
+ transform_state_t transforms;
+ vertex_cache_t vc;
+ prims_t prims;
+ culling_t cull;
+ lighting_t lighting;
+ user_clip_planes_t clipPlanes;
+ compute_iterators_t lerp; __attribute__((aligned(32)));
+ vertex_t current;
+ vec4_t currentColorClamped;
+ vec3_t currentNormal;
+ viewport_t viewport;
+ point_size_t point;
+ line_width_t line;
+ polygon_offset_t polygonOffset;
+ fog_t fog;
+ uint32_t perspective : 1;
+ uint32_t transformTextures : 1;
+ EGLSurfaceManager* surfaceManager;
+ EGLBufferObjectManager* bufferObjectManager;
+ GLenum error;
+
+ static inline ogles_context_t* get() {
+ return getGlThreadSpecific();
+ }
+
+};
+
+}; // namespace gl
+}; // namespace android
+
+#endif // ANDROID_OPENGLES_CONTEXT_H
+
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h
new file mode 100644
index 0000000..b6fcd80
--- /dev/null
+++ b/include/private/ui/LayerState.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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_COMPOSER_LAYER_STATE_H
+#define ANDROID_COMPOSER_LAYER_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <ui/ISurfaceFlingerClient.h>
+#include <ui/Region.h>
+
+#include <private/ui/SharedState.h>
+
+namespace android {
+
+class Parcel;
+
+struct layer_state_t {
+
+ layer_state_t()
+ : surface(0), what(0),
+ x(0), y(0), z(0), w(0), h(0),
+ alpha(0), tint(0), flags(0), mask(0),
+ reserved(0)
+ {
+ matrix.dsdx = matrix.dtdy = 1.0f;
+ matrix.dsdy = matrix.dtdx = 0.0f;
+ }
+
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
+
+ struct matrix22_t {
+ float dsdx;
+ float dtdx;
+ float dsdy;
+ float dtdy;
+ };
+ SurfaceID surface;
+ uint32_t what;
+ int32_t x;
+ int32_t y;
+ uint32_t z;
+ uint32_t w;
+ uint32_t h;
+ float alpha;
+ uint32_t tint;
+ uint8_t flags;
+ uint8_t mask;
+ uint8_t reserved;
+ matrix22_t matrix;
+ // non POD must be last. see write/read
+ Region transparentRegion;
+};
+
+}; // namespace android
+
+#endif // ANDROID_COMPOSER_LAYER_STATE_H
+
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
new file mode 100644
index 0000000..546d0ad
--- /dev/null
+++ b/include/private/ui/SharedState.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007 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_UI_SHARED_STATE_H
+#define ANDROID_UI_SHARED_STATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+namespace android {
+
+/*
+ * These structures are shared between the composer process and its clients
+ */
+
+// ---------------------------------------------------------------------------
+
+struct surface_info_t { // 4 longs, 16 bytes
+ enum {
+ eBufferDirty = 0x01
+ };
+ uint16_t w;
+ uint16_t h;
+ uint16_t stride;
+ uint16_t bpr;
+ uint16_t reserved;
+ uint8_t format;
+ uint8_t flags;
+ ssize_t bits_offset;
+};
+
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_LAYERS_MAX = 31;
+
+enum { // layer_cblk_t swapState
+ eIndex = 0x00000001,
+ eFlipRequested = 0x00000002,
+
+ eResizeBuffer0 = 0x00000004,
+ eResizeBuffer1 = 0x00000008,
+ eResizeRequested = eResizeBuffer0 | eResizeBuffer1,
+
+ eBusy = 0x00000010,
+ eLocked = 0x00000020,
+ eNextFlipPending = 0x00000040,
+ eInvalidSurface = 0x00000080
+};
+
+enum { // layer_cblk_t flags
+ eLayerNotPosted = 0x00000001,
+ eNoCopyBack = 0x00000002,
+ eReserved = 0x0000007C,
+ eBufferIndexShift = 7,
+ eBufferIndex = 1<<eBufferIndexShift,
+};
+
+struct flat_region_t // 40 bytes
+{
+ int32_t count;
+ int16_t l;
+ int16_t t;
+ int16_t r;
+ int16_t b;
+ uint16_t runs[14];
+};
+
+struct layer_cblk_t // (128 bytes)
+{
+ volatile int32_t swapState; // 4
+ volatile int32_t flags; // 4
+ volatile int32_t identity; // 4
+ int32_t reserved; // 4
+ surface_info_t surface[2]; // 32
+ flat_region_t region[2]; // 80
+
+ static inline int backBuffer(uint32_t state) {
+ return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
+ }
+ static inline int frontBuffer(uint32_t state) {
+ return 1 - backBuffer(state);
+ }
+};
+
+// ---------------------------------------------------------------------------
+
+struct per_client_cblk_t // 4KB max
+{
+ Mutex lock;
+ Condition cv;
+ layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
+
+ enum {
+ BLOCKING = 0x00000001,
+ INSPECT = 0x00000002
+ };
+
+ per_client_cblk_t();
+
+ // these functions are used by the clients
+ status_t validate(size_t i) const;
+ int32_t lock_layer(size_t i, uint32_t flags);
+ uint32_t unlock_layer_and_post(size_t i);
+ void unlock_layer(size_t i);
+};
+// ---------------------------------------------------------------------------
+
+const uint32_t NUM_DISPLAY_MAX = 4;
+
+struct display_cblk_t
+{
+ uint16_t w;
+ uint16_t h;
+ uint8_t format;
+ uint8_t orientation;
+ uint8_t reserved[2];
+ float fps;
+ float density;
+ float xdpi;
+ float ydpi;
+ uint32_t pad[2];
+};
+
+struct surface_flinger_cblk_t // 4KB max
+{
+ surface_flinger_cblk_t();
+
+ uint8_t connected;
+ uint8_t reserved[3];
+ uint32_t pad[7];
+
+ display_cblk_t displays[NUM_DISPLAY_MAX];
+};
+
+// ---------------------------------------------------------------------------
+
+template<bool> struct CTA;
+template<> struct CTA<true> { };
+
+// compile-time assertions. just to avoid catastrophes.
+inline void compile_time_asserts() {
+ CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
+ (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
+ CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
+ (void)sizeof__per_client_cblk_t__le_4096; // we don't want a warning
+ CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
+ (void)sizeof__surface_flinger_cblk_t__le_4096; // we don't want a warning
+}
+
+}; // namespace android
+
+#endif // ANDROID_UI_SHARED_STATE_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
new file mode 100644
index 0000000..ff91b61
--- /dev/null
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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_SURFACE_FLINGER_SYNCHRO_H
+#define ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <ui/ISurfaceComposer.h>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class SurfaceFlingerSynchro
+{
+public:
+
+ // client constructor
+ SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
+ ~SurfaceFlingerSynchro();
+
+ // signal surfaceflinger for some work
+ status_t signal();
+
+private:
+ class Barrier {
+ public:
+ Barrier();
+ ~Barrier();
+ void open();
+ void close();
+ void waitAndClose();
+ status_t waitAndClose(nsecs_t timeout);
+ private:
+ enum { OPENED, CLOSED };
+ mutable Mutex lock;
+ mutable Condition cv;
+ volatile int state;
+ };
+
+ friend class SurfaceFlinger;
+
+ // server constructor
+ SurfaceFlingerSynchro();
+
+ void open();
+
+ // wait until there is some work to do
+ status_t wait();
+ status_t wait(nsecs_t timeout);
+
+ sp<ISurfaceComposer> mSurfaceComposer;
+ Barrier mBarrier;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SURFACE_FLINGER_SYNCHRO_H
+
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
new file mode 100644
index 0000000..f1439b7
--- /dev/null
+++ b/include/private/utils/Static.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#ifndef LIBUTILS_NATIVE
+#include <utils/IBinder.h>
+#include <utils/IMemory.h>
+#include <utils/ProcessState.h>
+#include <utils/IPermissionController.h>
+#include <utils/IServiceManager.h>
+#endif
+
+namespace android {
+// For TextStream.cpp
+extern Vector<int32_t> gTextBuffers;
+
+// For String8.cpp
+extern void initialize_string8();
+extern void terminate_string8();
+
+// For String16.cpp
+extern void initialize_string16();
+extern void terminate_string16();
+
+
+
+#ifndef LIBUTILS_NATIVE
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+#endif
+
+} // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/utils/binder_module.h
new file mode 100644
index 0000000..fdf327e
--- /dev/null
+++ b/include/private/utils/binder_module.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 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 _BINDER_MODULE_H_
+#define _BINDER_MODULE_H_
+
+#ifdef __cplusplus
+namespace android {
+#endif
+
+#if defined(HAVE_ANDROID_OS)
+
+/* obtain structures and constants from the kernel header */
+
+#include <sys/ioctl.h>
+#include <linux/binder.h>
+
+#else
+
+/* Some parts of the simulator need fake versions of this
+ * stuff in order to compile. Really this should go away
+ * entirely...
+ */
+
+#define BINDER_CURRENT_PROTOCOL_VERSION 7
+
+#define BINDER_TYPE_BINDER 1
+#define BINDER_TYPE_WEAK_BINDER 2
+#define BINDER_TYPE_HANDLE 3
+#define BINDER_TYPE_WEAK_HANDLE 4
+#define BINDER_TYPE_FD 5
+
+struct flat_binder_object {
+ unsigned long type;
+ unsigned long flags;
+ union {
+ void *binder;
+ signed long handle;
+ };
+ void *cookie;
+};
+
+struct binder_write_read {
+ signed long write_size;
+ signed long write_consumed;
+ unsigned long write_buffer;
+ signed long read_size;
+ signed long read_consumed;
+ unsigned long read_buffer;
+};
+
+struct binder_transaction_data {
+ union {
+ size_t handle;
+ void *ptr;
+ } target;
+ void *cookie;
+ unsigned int code;
+
+ unsigned int flags;
+ pid_t sender_pid;
+ uid_t sender_euid;
+ size_t data_size;
+ size_t offsets_size;
+
+ union {
+ struct {
+ const void *buffer;
+ const void *offsets;
+ } ptr;
+ uint8_t buf[8];
+ } data;
+};
+
+enum transaction_flags {
+ TF_ONE_WAY = 0x01,
+ TF_ROOT_OBJECT = 0x04,
+ TF_STATUS_CODE = 0x08,
+ TF_ACCEPT_FDS = 0x10,
+};
+
+
+enum {
+ FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
+ FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
+};
+
+enum BinderDriverReturnProtocol {
+ BR_ERROR,
+ BR_OK,
+ BR_TRANSACTION,
+ BR_REPLY,
+ BR_ACQUIRE_RESULT,
+ BR_DEAD_REPLY,
+ BR_TRANSACTION_COMPLETE,
+ BR_INCREFS,
+ BR_ACQUIRE,
+ BR_RELEASE,
+ BR_DECREFS,
+ BR_ATTEMPT_ACQUIRE,
+ BR_NOOP,
+ BR_SPAWN_LOOPER,
+ BR_FINISHED,
+ BR_DEAD_BINDER,
+ BR_CLEAR_DEATH_NOTIFICATION_DONE,
+ BR_FAILED_REPLY,
+};
+
+enum BinderDriverCommandProtocol {
+ BC_TRANSACTION,
+ BC_REPLY,
+ BC_ACQUIRE_RESULT,
+ BC_FREE_BUFFER,
+ BC_INCREFS,
+ BC_ACQUIRE,
+ BC_RELEASE,
+ BC_DECREFS,
+ BC_INCREFS_DONE,
+ BC_ACQUIRE_DONE,
+ BC_ATTEMPT_ACQUIRE,
+ BC_REGISTER_LOOPER,
+ BC_ENTER_LOOPER,
+ BC_EXIT_LOOPER,
+ BC_REQUEST_DEATH_NOTIFICATION,
+ BC_CLEAR_DEATH_NOTIFICATION,
+ BC_DEAD_BINDER_DONE,
+};
+
+#endif
+
+#ifdef __cplusplus
+} // namespace android
+#endif
+
+#endif // _BINDER_MODULE_H_
diff --git a/include/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
new file mode 100644
index 0000000..ac2ab19
--- /dev/null
+++ b/include/private/utils/futex_synchro.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 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 _FUTEX_SYNCHRO_H
+#define _FUTEX_SYNCHRO_H
+
+#ifndef HAVE_FUTEX
+#error "HAVE_FUTEX not defined"
+#endif
+
+#define FUTEX_WAIT_INFINITE (0)
+
+typedef struct futex_mutex_t futex_mutex_t;
+
+struct futex_mutex_t
+{
+ volatile int value;
+};
+
+typedef struct futex_cond_t futex_cond_t;
+
+struct futex_cond_t
+{
+ volatile int value;
+};
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void futex_mutex_init(futex_mutex_t *m);
+int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
+void futex_mutex_unlock(futex_mutex_t *m);
+int futex_mutex_trylock(futex_mutex_t *m);
+
+void futex_cond_init(futex_cond_t *c);
+int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
+void futex_cond_signal(futex_cond_t *c);
+void futex_cond_broadcast(futex_cond_t *c);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FUTEX_SYNCHRO_H
+
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
new file mode 100644
index 0000000..8020da2
--- /dev/null
+++ b/media/libmedia/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioTrack.cpp \
+ IAudioFlinger.cpp \
+ IAudioFlingerClient.cpp \
+ IAudioTrack.cpp \
+ IAudioRecord.cpp \
+ AudioRecord.cpp \
+ AudioSystem.cpp \
+ mediaplayer.cpp \
+ IMediaPlayerService.cpp \
+ IMediaPlayerClient.cpp \
+ IMediaPlayer.cpp \
+ IMediaRecorder.cpp \
+ mediarecorder.cpp \
+ IMediaMetadataRetriever.cpp \
+ mediametadataretriever.cpp \
+ ToneGenerator.cpp \
+ JetPlayer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libui libcutils libutils libsonivox
+
+LOCAL_MODULE:= libmedia
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, graphics corecg)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
new file mode 100644
index 0000000..7594ff0
--- /dev/null
+++ b/media/libmedia/AudioRecord.cpp
@@ -0,0 +1,574 @@
+/*
+**
+** Copyright 2008, 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_NDEBUG 0
+#define LOG_TAG "AudioRecord"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioRecord.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioRecord::AudioRecord()
+ : mStatus(NO_INIT)
+{
+}
+
+AudioRecord::AudioRecord(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ callback_t cbf,
+ void* user,
+ int notificationFrames)
+ : mStatus(NO_INIT)
+{
+ mStatus = set(streamType, sampleRate, format, channelCount,
+ frameCount, flags, cbf, user, notificationFrames);
+}
+
+AudioRecord::~AudioRecord()
+{
+ if (mStatus == NO_ERROR) {
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer empty condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mClientRecordThread != 0) {
+ mCblk->cv.signal();
+ mClientRecordThread->requestExitAndWait();
+ mClientRecordThread.clear();
+ }
+ mAudioRecord.clear();
+ IPCThreadState::self()->flushCommands();
+ }
+}
+
+status_t AudioRecord::set(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ callback_t cbf,
+ void* user,
+ int notificationFrames,
+ bool threadCanCallJava)
+{
+
+ LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
+ if (mAudioFlinger != 0) {
+ return INVALID_OPERATION;
+ }
+
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ return NO_INIT;
+ }
+
+ if (streamType == DEFAULT_INPUT) {
+ streamType = MIC_INPUT;
+ }
+
+ if (sampleRate == 0) {
+ sampleRate = DEFAULT_SAMPLE_RATE;
+ }
+ // these below should probably come from the audioFlinger too...
+ if (format == 0) {
+ format = AudioSystem::PCM_16_BIT;
+ }
+ if (channelCount == 0) {
+ channelCount = 1;
+ }
+
+ // validate parameters
+ if (format != AudioSystem::PCM_16_BIT) {
+ return BAD_VALUE;
+ }
+ if (channelCount != 1 && channelCount != 2) {
+ return BAD_VALUE;
+ }
+
+ // 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;
+ } else if (frameCount < minFrameCount) {
+ return BAD_VALUE;
+ }
+
+ if (notificationFrames == 0) {
+ notificationFrames = frameCount/2;
+ }
+
+ // open record channel
+ status_t status;
+ sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
+ sampleRate, format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ &status);
+ if (record == 0) {
+ LOGE("AudioFlinger could not create record track, status: %d", status);
+ return status;
+ }
+ sp<IMemory> cblk = record->getCblk();
+ if (cblk == 0) {
+ return NO_INIT;
+ }
+ if (cbf != 0) {
+ mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
+ if (mClientRecordThread == 0) {
+ return NO_INIT;
+ }
+ }
+
+ mStatus = NO_ERROR;
+
+ mAudioFlinger = audioFlinger;
+ mAudioRecord = record;
+ mCblkMemory = cblk;
+ mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->out = 0;
+ mSampleRate = sampleRate;
+ mFormat = format;
+ // Update buffer size in case it has been limited by AudioFlinger during track creation
+ mFrameCount = mCblk->frameCount;
+ mChannelCount = channelCount;
+ mActive = 0;
+ mCbf = cbf;
+ mNotificationFrames = notificationFrames;
+ mRemainingFrames = notificationFrames;
+ mUserData = user;
+ // TODO: add audio hardware input latency here
+ mLatency = (1000*mFrameCount) / mSampleRate;
+ mMarkerPosition = 0;
+ mNewPosition = 0;
+ mUpdatePeriod = 0;
+
+ return NO_ERROR;
+}
+
+status_t AudioRecord::initCheck() const
+{
+ return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+uint32_t AudioRecord::latency() const
+{
+ return mLatency;
+}
+
+uint32_t AudioRecord::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioRecord::format() const
+{
+ return mFormat;
+}
+
+int AudioRecord::channelCount() const
+{
+ return mChannelCount;
+}
+
+uint32_t AudioRecord::frameCount() const
+{
+ return mFrameCount;
+}
+
+int AudioRecord::frameSize() const
+{
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::start()
+{
+ status_t ret = NO_ERROR;
+ sp<ClientRecordThread> t = mClientRecordThread;
+
+ LOGV("start");
+
+ if (t != 0) {
+ if (t->exitPending()) {
+ if (t->requestExitAndWait() == WOULD_BLOCK) {
+ LOGE("AudioRecord::start called from thread");
+ return WOULD_BLOCK;
+ }
+ }
+ t->mLock.lock();
+ }
+
+ if (android_atomic_or(1, &mActive) == 0) {
+ mNewPosition = mCblk->user + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
+ if (t != 0) {
+ t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ } else {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ ret = mAudioRecord->start();
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+
+ return ret;
+}
+
+status_t AudioRecord::stop()
+{
+ sp<ClientRecordThread> t = mClientRecordThread;
+
+ LOGV("stop");
+
+ if (t != 0) {
+ t->mLock.lock();
+ }
+
+ if (android_atomic_and(~1, &mActive) == 1) {
+ mAudioRecord->stop();
+ if (t != 0) {
+ t->requestExit();
+ } else {
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+ }
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+
+ return NO_ERROR;
+}
+
+bool AudioRecord::stopped() const
+{
+ return !mActive;
+}
+
+status_t AudioRecord::setMarkerPosition(uint32_t marker)
+{
+ if (mCbf == 0) return INVALID_OPERATION;
+
+ mMarkerPosition = marker;
+
+ return NO_ERROR;
+}
+
+status_t AudioRecord::getMarkerPosition(uint32_t *marker)
+{
+ if (marker == 0) return BAD_VALUE;
+
+ *marker = mMarkerPosition;
+
+ return NO_ERROR;
+}
+
+status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+ if (mCbf == 0) return INVALID_OPERATION;
+
+ uint32_t curPosition;
+ getPosition(&curPosition);
+ mNewPosition = curPosition + updatePeriod;
+ mUpdatePeriod = updatePeriod;
+
+ return NO_ERROR;
+}
+
+status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+ if (updatePeriod == 0) return BAD_VALUE;
+
+ *updatePeriod = mUpdatePeriod;
+
+ return NO_ERROR;
+}
+
+status_t AudioRecord::getPosition(uint32_t *position)
+{
+ if (position == 0) return BAD_VALUE;
+
+ *position = mCblk->user;
+
+ return NO_ERROR;
+}
+
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+{
+ int active;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+ uint32_t framesReq = audioBuffer->frameCount;
+
+ audioBuffer->frameCount = 0;
+ audioBuffer->size = 0;
+
+ uint32_t framesReady = cblk->framesReady();
+
+ if (framesReady == 0) {
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (framesReady == 0) {
+ active = mActive;
+ if (UNLIKELY(!active))
+ return NO_MORE_BUFFERS;
+ if (UNLIKELY(!waitCount))
+ return WOULD_BLOCK;
+ timeout = 0;
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+ 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);
+ timeout = 1;
+ cblk->waitTimeMs = 0;
+ }
+ if (--waitCount == 0) {
+ return TIMED_OUT;
+ }
+ }
+ // read the server count again
+ start_loop_here:
+ framesReady = cblk->framesReady();
+ }
+ }
+
+ LOGW_IF(timeout,
+ "*** SERIOUS WARNING *** obtainBuffer() timed out "
+ "but didn't need to be locked. We recovered, but "
+ "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+
+ cblk->waitTimeMs = 0;
+
+ if (framesReq > framesReady) {
+ framesReq = framesReady;
+ }
+
+ uint32_t u = cblk->user;
+ uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+ if (u + framesReq > bufferEnd) {
+ framesReq = bufferEnd - u;
+ }
+
+ audioBuffer->flags = 0;
+ audioBuffer->channelCount= mChannelCount;
+ audioBuffer->format = mFormat;
+ audioBuffer->frameCount = framesReq;
+ audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+ audioBuffer->raw = (int8_t*)cblk->buffer(u);
+ active = mActive;
+ return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioRecord::releaseBuffer(Buffer* audioBuffer)
+{
+ audio_track_cblk_t* cblk = mCblk;
+ cblk->stepUser(audioBuffer->frameCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioRecord::read(void* buffer, size_t userSize)
+{
+ ssize_t read = 0;
+ Buffer audioBuffer;
+ int8_t *dst = static_cast<int8_t*>(buffer);
+
+ if (ssize_t(userSize) < 0) {
+ // sanity-check. user is most-likely passing an error code.
+ LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
+ buffer, userSize, userSize);
+ return BAD_VALUE;
+ }
+
+ LOGV("read size: %d", userSize);
+
+ do {
+
+ audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+
+ // Calling obtainBuffer() with a negative wait count causes
+ // an (almost) infinite wait time.
+ status_t err = obtainBuffer(&audioBuffer, -1);
+ if (err < 0) {
+ // out of buffers, return #bytes written
+ if (err == status_t(NO_MORE_BUFFERS))
+ break;
+ return ssize_t(err);
+ }
+
+ size_t bytesRead = audioBuffer.size;
+ memcpy(dst, audioBuffer.i8, bytesRead);
+
+ dst += bytesRead;
+ userSize -= bytesRead;
+ read += bytesRead;
+
+ releaseBuffer(&audioBuffer);
+ } while (userSize);
+
+ return read;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
+{
+ Buffer audioBuffer;
+ uint32_t frames = mRemainingFrames;
+ size_t readSize;
+
+ // Manage marker callback
+ if (mMarkerPosition > 0) {
+ if (mCblk->user >= mMarkerPosition) {
+ mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+ mMarkerPosition = 0;
+ }
+ }
+
+ // Manage new position callback
+ if (mUpdatePeriod > 0) {
+ while (mCblk->user >= mNewPosition) {
+ mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+ mNewPosition += mUpdatePeriod;
+ }
+ }
+
+ do {
+ audioBuffer.frameCount = frames;
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // stuck here not being able to handle timed events (position, markers).
+ status_t err = obtainBuffer(&audioBuffer, 1);
+ if (err < NO_ERROR) {
+ if (err != TIMED_OUT) {
+ LOGE("Error obtaining an audio buffer, giving up.");
+ return false;
+ }
+ break;
+ }
+ if (err == status_t(STOPPED)) return false;
+
+ size_t reqSize = audioBuffer.size;
+ mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+ readSize = audioBuffer.size;
+
+ // Sanity check on returned size
+ if (ssize_t(readSize) <= 0) break;
+ if (readSize > reqSize) readSize = reqSize;
+
+ audioBuffer.size = readSize;
+ audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+ frames -= audioBuffer.frameCount;
+
+ releaseBuffer(&audioBuffer);
+
+ } while (frames);
+
+
+ // Manage overrun callback
+ if (mActive && (mCblk->framesAvailable_l() == 0)) {
+ LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+ if (mCblk->flowControlFlag == 0) {
+ mCbf(EVENT_OVERRUN, mUserData, 0);
+ mCblk->flowControlFlag = 1;
+ }
+ }
+
+ if (frames == 0) {
+ mRemainingFrames = mNotificationFrames;
+ } else {
+ mRemainingFrames = frames;
+ }
+ return true;
+}
+
+// =========================================================================
+
+AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
+ : Thread(bCanCallJava), mReceiver(receiver)
+{
+}
+
+bool AudioRecord::ClientRecordThread::threadLoop()
+{
+ return mReceiver.processAudioBuffer(this);
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
new file mode 100644
index 0000000..63dfc3b
--- /dev/null
+++ b/media/libmedia/AudioSystem.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2006-2007 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 "AudioSystem"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/IServiceManager.h>
+#include <media/AudioSystem.h>
+#include <math.h>
+
+namespace android {
+
+// client singleton for AudioFlinger binder interface
+Mutex AudioSystem::gLock;
+sp<IAudioFlinger> AudioSystem::gAudioFlinger;
+sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
+audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
+// Cached values
+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
+const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
+{
+ Mutex::Autolock _l(gLock);
+ if (gAudioFlinger.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_flinger"));
+ if (binder != 0)
+ break;
+ LOGW("AudioFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (gAudioFlingerClient == NULL) {
+ gAudioFlingerClient = new AudioFlingerClient();
+ } else {
+ if (gAudioErrorCallback) {
+ gAudioErrorCallback(NO_ERROR);
+ }
+ }
+ binder->linkToDeath(gAudioFlingerClient);
+ gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+ gAudioFlinger->registerClient(gAudioFlingerClient);
+ // Cache frequently accessed parameters
+ 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;
+}
+
+// routing helper functions
+status_t AudioSystem::speakerphone(bool state) {
+ uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
+ return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isSpeakerphoneOn(bool* state) {
+ uint32_t routes = 0;
+ status_t s = getRouting(MODE_IN_CALL, &routes);
+ *state = !!(routes & ROUTE_SPEAKER);
+ return s;
+}
+
+status_t AudioSystem::bluetoothSco(bool state) {
+ uint32_t mask = ROUTE_BLUETOOTH_SCO;
+ uint32_t routes = state ? mask : ROUTE_EARPIECE;
+ return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isBluetoothScoOn(bool* state) {
+ uint32_t routes = 0;
+ status_t s = getRouting(MODE_IN_CALL, &routes);
+ *state = !!(routes & ROUTE_BLUETOOTH_SCO);
+ return s;
+}
+
+status_t AudioSystem::muteMicrophone(bool state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setMicMute(state);
+}
+
+status_t AudioSystem::isMicrophoneMuted(bool* state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *state = af->getMicMute();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterVolume(float value)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setMasterVolume(value);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterMute(bool mute)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setMasterMute(mute);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterVolume(float* volume)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *volume = af->masterVolume();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterMute(bool* mute)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *mute = af->masterMute();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamVolume(int stream, float 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);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamMute(int stream, bool mute)
+{
+ 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);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamVolume(int stream, float* volume)
+{
+ 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);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamMute(int stream, bool* mute)
+{
+ 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);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMode(int mode)
+{
+ if (mode >= NUM_MODES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setMode(mode);
+}
+
+status_t AudioSystem::getMode(int* mode)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *mode = af->getMode();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setRouting(mode, routes, mask);
+}
+
+status_t AudioSystem::getRouting(int mode, uint32_t* routes)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ uint32_t r = af->getRouting(mode);
+ *routes = r;
+ return NO_ERROR;
+}
+
+status_t AudioSystem::isMusicActive(bool* state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *state = af->isMusicActive();
+ return NO_ERROR;
+}
+
+// Temporary interface, do not use
+// TODO: Replace with a more generic key:value get/set mechanism
+status_t AudioSystem::setParameter(const char* key, const char* value) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setParameter(key, value);
+}
+
+// convert volume steps to natural log scale
+
+// change this value to change volume scaling
+static const float dBPerStep = 0.5f;
+// shouldn't need to touch these
+static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
+static const float dBConvertInverse = 1.0f / dBConvert;
+
+float AudioSystem::linearToLog(int volume)
+{
+ // float v = volume ? exp(float(100 - volume) * dBConvert) : 0;
+ // LOGD("linearToLog(%d)=%f", volume, v);
+ // return v;
+ return volume ? exp(float(100 - volume) * dBConvert) : 0;
+}
+
+int AudioSystem::logToLinear(float volume)
+{
+ // int v = volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+ // LOGD("logTolinear(%d)=%f", v, volume);
+ // return v;
+ return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+}
+
+status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
+{
+ 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()
+ }
+ 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, int streamType)
+{
+ int output = getOutput(streamType);
+
+ if (gOutFrameCount[output] == 0) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ // gOutFrameCount is updated by get_audio_flinger()
+ }
+ 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, int streamType)
+{
+ 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()
+ }
+ 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::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ AudioSystem::gAudioFlinger.clear();
+
+ 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
new file mode 100644
index 0000000..e79f336
--- /dev/null
+++ b/media/libmedia/AudioTrack.cpp
@@ -0,0 +1,1021 @@
+/* //device/extlibs/pv/android/AudioTrack.cpp
+**
+** Copyright 2007, 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_NDEBUG 0
+#define LOG_TAG "AudioTrack"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioTrack::AudioTrack()
+ : mStatus(NO_INIT)
+{
+}
+
+AudioTrack::AudioTrack(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ callback_t cbf,
+ void* user,
+ int notificationFrames)
+ : mStatus(NO_INIT)
+{
+ mStatus = set(streamType, sampleRate, format, channelCount,
+ frameCount, flags, cbf, user, notificationFrames, 0);
+}
+
+AudioTrack::AudioTrack(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ const sp<IMemory>& sharedBuffer,
+ uint32_t flags,
+ callback_t cbf,
+ void* user,
+ int notificationFrames)
+ : mStatus(NO_INIT)
+{
+ mStatus = set(streamType, sampleRate, format, channelCount,
+ 0, flags, cbf, user, notificationFrames, sharedBuffer);
+}
+
+AudioTrack::~AudioTrack()
+{
+ LOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
+
+ if (mStatus == NO_ERROR) {
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer full condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mAudioTrackThread != 0) {
+ mCblk->cv.signal();
+ mAudioTrackThread->requestExitAndWait();
+ mAudioTrackThread.clear();
+ }
+ mAudioTrack.clear();
+ IPCThreadState::self()->flushCommands();
+ }
+}
+
+status_t AudioTrack::set(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ callback_t cbf,
+ void* user,
+ int notificationFrames,
+ const sp<IMemory>& sharedBuffer,
+ bool threadCanCallJava)
+{
+
+ LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+ if (mAudioFlinger != 0) {
+ LOGE("Track already in use");
+ return INVALID_OPERATION;
+ }
+
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ LOGE("Could not get audioflinger");
+ return NO_INIT;
+ }
+ int afSampleRate;
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ int afFrameCount;
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ uint32_t afLatency;
+ if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+
+ // handle default values first.
+ if (streamType == AudioSystem::DEFAULT) {
+ streamType = AudioSystem::MUSIC;
+ }
+ if (sampleRate == 0) {
+ sampleRate = afSampleRate;
+ }
+ // these below should probably come from the audioFlinger too...
+ if (format == 0) {
+ format = AudioSystem::PCM_16_BIT;
+ }
+ if (channelCount == 0) {
+ channelCount = 2;
+ }
+
+ // validate parameters
+ if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
+ (format != AudioSystem::PCM_16_BIT)) {
+ LOGE("Invalid format");
+ return BAD_VALUE;
+ }
+ if (channelCount != 1 && channelCount != 2) {
+ LOGE("Invalid channel number");
+ return BAD_VALUE;
+ }
+
+ // 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) {
+ minBufCount--;
+ }
+
+ int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+ if (sharedBuffer == 0) {
+ if (frameCount == 0) {
+ frameCount = minFrameCount;
+ }
+ if (notificationFrames == 0) {
+ notificationFrames = frameCount/2;
+ }
+ // Make sure that application is notified with sufficient margin
+ // before underrun
+ if (notificationFrames > frameCount/2) {
+ notificationFrames = frameCount/2;
+ }
+ } else {
+ // Ensure that buffer alignment matches channelcount
+ if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+ LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+ return BAD_VALUE;
+ }
+ frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+ }
+
+ if (frameCount < minFrameCount) {
+ LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+ return BAD_VALUE;
+ }
+
+ // create the track
+ status_t status;
+ sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
+ streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+
+ if (track == 0) {
+ LOGE("AudioFlinger could not create track, status: %d", status);
+ return status;
+ }
+ sp<IMemory> cblk = track->getCblk();
+ if (cblk == 0) {
+ LOGE("Could not get control block");
+ return NO_INIT;
+ }
+ if (cbf != 0) {
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ if (mAudioTrackThread == 0) {
+ LOGE("Could not create callback thread");
+ return NO_INIT;
+ }
+ }
+
+ mStatus = NO_ERROR;
+
+ mAudioFlinger = audioFlinger;
+ mAudioTrack = track;
+ mCblkMemory = cblk;
+ mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+ mCblk->out = 1;
+ // Update buffer size in case it has been limited by AudioFlinger during track creation
+ mFrameCount = mCblk->frameCount;
+ if (sharedBuffer == 0) {
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ } else {
+ mCblk->buffers = sharedBuffer->pointer();
+ // Force buffer full condition as data is already present in shared memory
+ mCblk->stepUser(mFrameCount);
+ }
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mVolume[LEFT] = 1.0f;
+ mVolume[RIGHT] = 1.0f;
+ mSampleRate = sampleRate;
+ mStreamType = streamType;
+ mFormat = format;
+ mChannelCount = channelCount;
+ mSharedBuffer = sharedBuffer;
+ mMuted = false;
+ mActive = 0;
+ mCbf = cbf;
+ mNotificationFrames = notificationFrames;
+ mRemainingFrames = notificationFrames;
+ mUserData = user;
+ mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
+ mLoopCount = 0;
+ mMarkerPosition = 0;
+ mNewPosition = 0;
+ mUpdatePeriod = 0;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::initCheck() const
+{
+ return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+uint32_t AudioTrack::latency() const
+{
+ return mLatency;
+}
+
+int AudioTrack::streamType() const
+{
+ return mStreamType;
+}
+
+uint32_t AudioTrack::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioTrack::format() const
+{
+ return mFormat;
+}
+
+int AudioTrack::channelCount() const
+{
+ return mChannelCount;
+}
+
+uint32_t AudioTrack::frameCount() const
+{
+ return mFrameCount;
+}
+
+int AudioTrack::frameSize() const
+{
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+}
+
+sp<IMemory>& AudioTrack::sharedBuffer()
+{
+ return mSharedBuffer;
+}
+
+// -------------------------------------------------------------------------
+
+void AudioTrack::start()
+{
+ sp<AudioTrackThread> t = mAudioTrackThread;
+
+ LOGV("start %p", this);
+ if (t != 0) {
+ if (t->exitPending()) {
+ if (t->requestExitAndWait() == WOULD_BLOCK) {
+ LOGE("AudioTrack::start called from thread");
+ return;
+ }
+ }
+ t->mLock.lock();
+ }
+
+ if (android_atomic_or(1, &mActive) == 0) {
+ mNewPosition = mCblk->server + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
+ if (t != 0) {
+ t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ } else {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ mAudioTrack->start();
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+}
+
+void AudioTrack::stop()
+{
+ sp<AudioTrackThread> t = mAudioTrackThread;
+
+ LOGV("stop %p", this);
+ if (t != 0) {
+ t->mLock.lock();
+ }
+
+ if (android_atomic_and(~1, &mActive) == 1) {
+ mAudioTrack->stop();
+ // Cancel loops (If we are in the middle of a loop, playback
+ // would not stop until loopCount reaches 0).
+ setLoop(0, 0, 0);
+ // Force flush if a shared buffer is used otherwise audioflinger
+ // will not stop before end of buffer is reached.
+ if (mSharedBuffer != 0) {
+ flush();
+ }
+ if (t != 0) {
+ t->requestExit();
+ } else {
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+ }
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+}
+
+bool AudioTrack::stopped() const
+{
+ return !mActive;
+}
+
+void AudioTrack::flush()
+{
+ LOGV("flush");
+
+ if (!mActive) {
+ mCblk->lock.lock();
+ mAudioTrack->flush();
+ // Release AudioTrack callback thread in case it was waiting for new buffers
+ // in AudioTrack::obtainBuffer()
+ mCblk->cv.signal();
+ mCblk->lock.unlock();
+ }
+}
+
+void AudioTrack::pause()
+{
+ LOGV("pause");
+ if (android_atomic_and(~1, &mActive) == 1) {
+ mActive = 0;
+ mAudioTrack->pause();
+ }
+}
+
+void AudioTrack::mute(bool e)
+{
+ mAudioTrack->mute(e);
+ mMuted = e;
+}
+
+bool AudioTrack::muted() const
+{
+ return mMuted;
+}
+
+void AudioTrack::setVolume(float left, float right)
+{
+ mVolume[LEFT] = left;
+ mVolume[RIGHT] = right;
+
+ // write must be atomic
+ mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
+}
+
+void AudioTrack::getVolume(float* left, float* right)
+{
+ *left = mVolume[LEFT];
+ *right = mVolume[RIGHT];
+}
+
+void AudioTrack::setSampleRate(int rate)
+{
+ int afSamplingRate;
+
+ 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;
+}
+
+uint32_t AudioTrack::getSampleRate()
+{
+ return uint32_t(mCblk->sampleRate);
+}
+
+status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
+ audio_track_cblk_t* cblk = mCblk;
+
+
+ Mutex::Autolock _l(cblk->lock);
+
+ if (loopCount == 0) {
+ cblk->loopStart = UINT_MAX;
+ cblk->loopEnd = UINT_MAX;
+ cblk->loopCount = 0;
+ mLoopCount = 0;
+ return NO_ERROR;
+ }
+
+ if (loopStart >= loopEnd ||
+ loopEnd - loopStart > mFrameCount) {
+ LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+ return BAD_VALUE;
+ }
+
+ 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;
+ cblk->loopCount = loopCount;
+ mLoopCount = loopCount;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
+{
+ if (loopStart != 0) {
+ *loopStart = mCblk->loopStart;
+ }
+ if (loopEnd != 0) {
+ *loopEnd = mCblk->loopEnd;
+ }
+ if (loopCount != 0) {
+ if (mCblk->loopCount < 0) {
+ *loopCount = -1;
+ } else {
+ *loopCount = mCblk->loopCount;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::setMarkerPosition(uint32_t marker)
+{
+ if (mCbf == 0) return INVALID_OPERATION;
+
+ mMarkerPosition = marker;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::getMarkerPosition(uint32_t *marker)
+{
+ if (marker == 0) return BAD_VALUE;
+
+ *marker = mMarkerPosition;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+ if (mCbf == 0) return INVALID_OPERATION;
+
+ uint32_t curPosition;
+ getPosition(&curPosition);
+ mNewPosition = curPosition + updatePeriod;
+ mUpdatePeriod = updatePeriod;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+ if (updatePeriod == 0) return BAD_VALUE;
+
+ *updatePeriod = mUpdatePeriod;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::setPosition(uint32_t position)
+{
+ Mutex::Autolock _l(mCblk->lock);
+
+ if (!stopped()) return INVALID_OPERATION;
+
+ if (position > mCblk->user) return BAD_VALUE;
+
+ mCblk->server = position;
+ mCblk->forceReady = 1;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::getPosition(uint32_t *position)
+{
+ if (position == 0) return BAD_VALUE;
+
+ *position = mCblk->server;
+
+ return NO_ERROR;
+}
+
+status_t AudioTrack::reload()
+{
+ if (!stopped()) return INVALID_OPERATION;
+
+ flush();
+
+ mCblk->stepUser(mFrameCount);
+
+ return NO_ERROR;
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+{
+ int active;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+ uint32_t framesReq = audioBuffer->frameCount;
+
+ audioBuffer->frameCount = 0;
+ audioBuffer->size = 0;
+
+ uint32_t framesAvail = cblk->framesAvailable();
+
+ if (framesAvail == 0) {
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (framesAvail == 0) {
+ active = mActive;
+ if (UNLIKELY(!active)) {
+ LOGV("Not active and NO_MORE_BUFFERS");
+ return NO_MORE_BUFFERS;
+ }
+ if (UNLIKELY(!waitCount))
+ return WOULD_BLOCK;
+ timeout = 0;
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+ if (__builtin_expect(result!=NO_ERROR, false)) {
+ cblk->waitTimeMs += WAIT_PERIOD_MS;
+ if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+ // 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;
+ }
+ }
+ // read the server count again
+ start_loop_here:
+ framesAvail = cblk->framesAvailable_l();
+ }
+ }
+
+ cblk->waitTimeMs = 0;
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+
+ uint32_t u = cblk->user;
+ uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+ if (u + framesReq > bufferEnd) {
+ framesReq = bufferEnd - u;
+ }
+
+ LOGW_IF(timeout,
+ "*** SERIOUS WARNING *** obtainBuffer() timed out "
+ "but didn't need to be locked. We recovered, but "
+ "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+
+ audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+ audioBuffer->channelCount= mChannelCount;
+ audioBuffer->format = AudioSystem::PCM_16_BIT;
+ audioBuffer->frameCount = framesReq;
+ audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+ audioBuffer->raw = (int8_t *)cblk->buffer(u);
+ active = mActive;
+ return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioTrack::releaseBuffer(Buffer* audioBuffer)
+{
+ audio_track_cblk_t* cblk = mCblk;
+ cblk->stepUser(audioBuffer->frameCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+{
+
+ if (mSharedBuffer != 0) return INVALID_OPERATION;
+
+ if (ssize_t(userSize) < 0) {
+ // sanity-check. user is most-likely passing an error code.
+ LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
+ buffer, userSize, userSize);
+ return BAD_VALUE;
+ }
+
+ LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
+
+ ssize_t written = 0;
+ const int8_t *src = (const int8_t *)buffer;
+ Buffer audioBuffer;
+
+ do {
+ audioBuffer.frameCount = userSize/mChannelCount;
+ if (mFormat == AudioSystem::PCM_16_BIT) {
+ audioBuffer.frameCount >>= 1;
+ }
+ // Calling obtainBuffer() with a negative wait count causes
+ // an (almost) infinite wait time.
+ status_t err = obtainBuffer(&audioBuffer, -1);
+ if (err < 0) {
+ // out of buffers, return #bytes written
+ if (err == status_t(NO_MORE_BUFFERS))
+ break;
+ return ssize_t(err);
+ }
+
+ size_t toWrite;
+ if (mFormat == AudioSystem::PCM_8_BIT) {
+ // Divide capacity by 2 to take expansion into account
+ toWrite = audioBuffer.size>>1;
+ // 8 to 16 bit conversion
+ int count = toWrite;
+ int16_t *dst = (int16_t *)(audioBuffer.i8);
+ while(count--) {
+ *dst++ = (int16_t)(*src++^0x80) << 8;
+ }
+ }else {
+ toWrite = audioBuffer.size;
+ memcpy(audioBuffer.i8, src, toWrite);
+ src += toWrite;
+ }
+ userSize -= toWrite;
+ written += toWrite;
+
+ releaseBuffer(&audioBuffer);
+ } while (userSize);
+
+ return written;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+{
+ Buffer audioBuffer;
+ uint32_t frames;
+ size_t writtenSize;
+
+ // Manage underrun callback
+ if (mActive && (mCblk->framesReady() == 0)) {
+ LOGV("Underrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+ if (mCblk->flowControlFlag == 0) {
+ mCbf(EVENT_UNDERRUN, mUserData, 0);
+ if (mCblk->server == mCblk->frameCount) {
+ mCbf(EVENT_BUFFER_END, mUserData, 0);
+ }
+ mCblk->flowControlFlag = 1;
+ if (mSharedBuffer != 0) return false;
+ }
+ }
+
+ // Manage loop end callback
+ while (mLoopCount > mCblk->loopCount) {
+ int loopCount = -1;
+ mLoopCount--;
+ if (mLoopCount >= 0) loopCount = mLoopCount;
+
+ mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
+ }
+
+ // Manage marker callback
+ if(mMarkerPosition > 0) {
+ if (mCblk->server >= mMarkerPosition) {
+ mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+ mMarkerPosition = 0;
+ }
+ }
+
+ // Manage new position callback
+ if(mUpdatePeriod > 0) {
+ while (mCblk->server >= mNewPosition) {
+ mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+ mNewPosition += mUpdatePeriod;
+ }
+ }
+
+ // If Shared buffer is used, no data is requested from client.
+ if (mSharedBuffer != 0) {
+ frames = 0;
+ } else {
+ frames = mRemainingFrames;
+ }
+
+ do {
+
+ audioBuffer.frameCount = frames;
+
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // stuck here not being able to handle timed events (position, markers, loops).
+ status_t err = obtainBuffer(&audioBuffer, 1);
+ if (err < NO_ERROR) {
+ if (err != TIMED_OUT) {
+ LOGE("Error obtaining an audio buffer, giving up.");
+ return false;
+ }
+ break;
+ }
+ if (err == status_t(STOPPED)) return false;
+
+ // Divide buffer size by 2 to take into account the expansion
+ // due to 8 to 16 bit conversion: the callback must fill only half
+ // of the destination buffer
+ if (mFormat == AudioSystem::PCM_8_BIT) {
+ audioBuffer.size >>= 1;
+ }
+
+ size_t reqSize = audioBuffer.size;
+ mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+ writtenSize = audioBuffer.size;
+
+ // Sanity check on returned size
+ if (ssize_t(writtenSize) <= 0) break;
+ if (writtenSize > reqSize) writtenSize = reqSize;
+
+ if (mFormat == AudioSystem::PCM_8_BIT) {
+ // 8 to 16 bit conversion
+ const int8_t *src = audioBuffer.i8 + writtenSize-1;
+ int count = writtenSize;
+ int16_t *dst = audioBuffer.i16 + writtenSize-1;
+ while(count--) {
+ *dst-- = (int16_t)(*src--^0x80) << 8;
+ }
+ writtenSize <<= 1;
+ }
+
+ audioBuffer.size = writtenSize;
+ audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+ frames -= audioBuffer.frameCount;
+
+ releaseBuffer(&audioBuffer);
+ }
+ while (frames);
+
+ if (frames == 0) {
+ mRemainingFrames = mNotificationFrames;
+ } else {
+ mRemainingFrames = frames;
+ }
+ return true;
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+{
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append(" AudioTrack::dump\n");
+ snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
+ result.append(buffer);
+ snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
+ result.append(buffer);
+ snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
+ result.append(buffer);
+ snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// =========================================================================
+
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
+ : Thread(bCanCallJava), mReceiver(receiver)
+{
+}
+
+bool AudioTrack::AudioTrackThread::threadLoop()
+{
+ return mReceiver.processAudioBuffer(this);
+}
+
+status_t AudioTrack::AudioTrackThread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+void AudioTrack::AudioTrackThread::onFirstRef()
+{
+}
+
+// =========================================================================
+
+audio_track_cblk_t::audio_track_cblk_t()
+ : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+ loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
+{
+}
+
+uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
+{
+ uint32_t u = this->user;
+
+ u += frameCount;
+ // Ensure that user is never ahead of server for AudioRecord
+ if (out) {
+ // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
+ if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
+ bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ }
+ } else if (u > this->server) {
+ LOGW("stepServer occured after track reset");
+ u = this->server;
+ }
+
+ if (u >= userBase + this->frameCount) {
+ userBase += this->frameCount;
+ }
+
+ this->user = u;
+
+ // Clear flow control error condition as new data has been written/read to/from buffer.
+ flowControlFlag = 0;
+
+ return u;
+}
+
+bool audio_track_cblk_t::stepServer(uint32_t frameCount)
+{
+ // the code below simulates lock-with-timeout
+ // we MUST do this to protect the AudioFlinger server
+ // as this lock is shared with the client.
+ status_t err;
+
+ err = lock.tryLock();
+ if (err == -EBUSY) { // just wait a bit
+ usleep(1000);
+ err = lock.tryLock();
+ }
+ if (err != NO_ERROR) {
+ // probably, the client just died.
+ return false;
+ }
+
+ uint32_t s = this->server;
+
+ s += frameCount;
+ if (out) {
+ // Mark that we have read the first buffer so that next time stepUser() is called
+ // we switch to normal obtainBuffer() timeout period
+ if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
+ bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
+ }
+ // It is possible that we receive a flush()
+ // while the mixer is processing a block: in this case,
+ // stepServer() is called After the flush() has reset u & s and
+ // we have s > u
+ if (s > this->user) {
+ LOGW("stepServer occured after track reset");
+ s = this->user;
+ }
+ }
+
+ if (s >= loopEnd) {
+ LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
+ s = loopStart;
+ if (--loopCount == 0) {
+ loopEnd = UINT_MAX;
+ loopStart = UINT_MAX;
+ }
+ }
+ if (s >= serverBase + this->frameCount) {
+ serverBase += this->frameCount;
+ }
+
+ this->server = s;
+
+ cv.signal();
+ lock.unlock();
+ return true;
+}
+
+void* audio_track_cblk_t::buffer(uint32_t offset) const
+{
+ return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+}
+
+uint32_t audio_track_cblk_t::framesAvailable()
+{
+ Mutex::Autolock _l(lock);
+ return framesAvailable_l();
+}
+
+uint32_t audio_track_cblk_t::framesAvailable_l()
+{
+ uint32_t u = this->user;
+ uint32_t s = this->server;
+
+ if (out) {
+ uint32_t limit = (s < loopStart) ? s : loopStart;
+ return limit + frameCount - u;
+ } else {
+ return frameCount + u - s;
+ }
+}
+
+uint32_t audio_track_cblk_t::framesReady()
+{
+ uint32_t u = this->user;
+ uint32_t s = this->server;
+
+ if (out) {
+ if (u < loopEnd) {
+ return u - s;
+ } else {
+ Mutex::Autolock _l(lock);
+ if (loopCount >= 0) {
+ return (loopEnd - loopStart)*loopCount + u - s;
+ } else {
+ return UINT_MAX;
+ }
+ }
+ } else {
+ return s - u;
+ }
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
new file mode 100644
index 0000000..5cbb25c
--- /dev/null
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -0,0 +1,553 @@
+/* //device/extlibs/pv/android/IAudioflinger.cpp
+**
+** Copyright 2007, 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 "IAudioFlinger"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlinger.h>
+
+namespace android {
+
+enum {
+ CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
+ OPEN_RECORD,
+ SAMPLE_RATE,
+ CHANNEL_COUNT,
+ FORMAT,
+ FRAME_COUNT,
+ LATENCY,
+ SET_MASTER_VOLUME,
+ SET_MASTER_MUTE,
+ MASTER_VOLUME,
+ MASTER_MUTE,
+ SET_STREAM_VOLUME,
+ SET_STREAM_MUTE,
+ STREAM_VOLUME,
+ STREAM_MUTE,
+ SET_MODE,
+ GET_MODE,
+ SET_ROUTING,
+ GET_ROUTING,
+ SET_MIC_MUTE,
+ GET_MIC_MUTE,
+ IS_MUSIC_ACTIVE,
+ SET_PARAMETER,
+ REGISTER_CLIENT,
+ GET_INPUTBUFFERSIZE,
+ WAKE_UP,
+ IS_A2DP_ENABLED
+};
+
+class BpAudioFlinger : public BpInterface<IAudioFlinger>
+{
+public:
+ BpAudioFlinger(const sp<IBinder>& impl)
+ : BpInterface<IAudioFlinger>(impl)
+ {
+ }
+
+ virtual sp<IAudioTrack> createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(streamType);
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ data.writeInt32(frameCount);
+ data.writeInt32(flags);
+ data.writeStrongBinder(sharedBuffer->asBinder());
+ status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
+ if (lStatus != NO_ERROR) {
+ LOGE("createTrack error: %s", strerror(-lStatus));
+ }
+ lStatus = reply.readInt32();
+ if (status) {
+ *status = lStatus;
+ }
+ return interface_cast<IAudioTrack>(reply.readStrongBinder());
+ }
+
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ status_t *status)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(streamType);
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ data.writeInt32(frameCount);
+ data.writeInt32(flags);
+ remote()->transact(OPEN_RECORD, data, &reply);
+ status_t lStatus = reply.readInt32();
+ if (status) {
+ *status = lStatus;
+ }
+ return interface_cast<IAudioRecord>(reply.readStrongBinder());
+ }
+
+ 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(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(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(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(int output) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(LATENCY, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMasterVolume(float value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeFloat(value);
+ remote()->transact(SET_MASTER_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMasterMute(bool muted)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(muted);
+ remote()->transact(SET_MASTER_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual float masterVolume() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(MASTER_VOLUME, data, &reply);
+ return reply.readFloat();
+ }
+
+ virtual bool masterMute() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(MASTER_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamVolume(int stream, float value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeFloat(value);
+ remote()->transact(SET_STREAM_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamMute(int stream, bool muted)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeInt32(muted);
+ remote()->transact(SET_STREAM_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual float streamVolume(int stream) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ remote()->transact(STREAM_VOLUME, data, &reply);
+ return reply.readFloat();
+ }
+
+ virtual bool streamMute(int stream) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ remote()->transact(STREAM_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ data.writeInt32(routes);
+ data.writeInt32(mask);
+ remote()->transact(SET_ROUTING, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual uint32_t getRouting(int mode) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(GET_ROUTING, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMode(int mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_MODE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int getMode() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(GET_MODE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMicMute(bool state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(state);
+ remote()->transact(SET_MIC_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual bool getMicMute() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(GET_MIC_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual bool isMusicActive() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(IS_MUSIC_ACTIVE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setParameter(const char* key, const char* value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeCString(key);
+ data.writeCString(value);
+ 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");
+
+// ----------------------------------------------------------------------
+
+#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 BnAudioFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CREATE_TRACK: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ pid_t pid = data.readInt32();
+ int streamType = data.readInt32();
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ size_t bufferCount = data.readInt32();
+ uint32_t flags = data.readInt32();
+ sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+ status_t status;
+ sp<IAudioTrack> track = createTrack(pid,
+ streamType, sampleRate, format,
+ channelCount, bufferCount, flags, buffer, &status);
+ reply->writeInt32(status);
+ reply->writeStrongBinder(track->asBinder());
+ return NO_ERROR;
+ } break;
+ case OPEN_RECORD: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ pid_t pid = data.readInt32();
+ int streamType = data.readInt32();
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ size_t bufferCount = data.readInt32();
+ uint32_t flags = data.readInt32();
+ status_t status;
+ sp<IAudioRecord> record = openRecord(pid, streamType,
+ sampleRate, format, channelCount, bufferCount, flags, &status);
+ reply->writeInt32(status);
+ reply->writeStrongBinder(record->asBinder());
+ return NO_ERROR;
+ } break;
+ case SAMPLE_RATE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int output = data.readInt32();
+ reply->writeInt32( sampleRate(output) );
+ return NO_ERROR;
+ } break;
+ case CHANNEL_COUNT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int output = data.readInt32();
+ reply->writeInt32( channelCount(output) );
+ return NO_ERROR;
+ } break;
+ case FORMAT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int output = data.readInt32();
+ reply->writeInt32( format(output) );
+ return NO_ERROR;
+ } break;
+ case FRAME_COUNT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int output = data.readInt32();
+ reply->writeInt32( frameCount(output) );
+ return NO_ERROR;
+ } break;
+ case LATENCY: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int output = data.readInt32();
+ reply->writeInt32( latency(output) );
+ return NO_ERROR;
+ } break;
+ case SET_MASTER_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( setMasterVolume(data.readFloat()) );
+ return NO_ERROR;
+ } break;
+ case SET_MASTER_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( setMasterMute(data.readInt32()) );
+ return NO_ERROR;
+ } break;
+ case MASTER_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeFloat( masterVolume() );
+ return NO_ERROR;
+ } break;
+ case MASTER_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( masterMute() );
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( setStreamMute(stream, data.readInt32()) );
+ return NO_ERROR;
+ } break;
+ case STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeFloat( streamVolume(stream) );
+ return NO_ERROR;
+ } break;
+ case STREAM_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( streamMute(stream) );
+ return NO_ERROR;
+ } break;
+ case SET_ROUTING: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ uint32_t routes = data.readInt32();
+ uint32_t mask = data.readInt32();
+ reply->writeInt32( setRouting(mode, routes, mask) );
+ return NO_ERROR;
+ } break;
+ case GET_ROUTING: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ reply->writeInt32( getRouting(mode) );
+ return NO_ERROR;
+ } break;
+ case SET_MODE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ reply->writeInt32( setMode(mode) );
+ return NO_ERROR;
+ } break;
+ case GET_MODE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( getMode() );
+ return NO_ERROR;
+ } break;
+ case SET_MIC_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int state = data.readInt32();
+ reply->writeInt32( setMicMute(state) );
+ return NO_ERROR;
+ } break;
+ case GET_MIC_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( getMicMute() );
+ return NO_ERROR;
+ } break;
+ case IS_MUSIC_ACTIVE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( isMusicActive() );
+ return NO_ERROR;
+ } break;
+ case SET_PARAMETER: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ const char *key = data.readCString();
+ const char *value = data.readCString();
+ 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);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
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/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
new file mode 100644
index 0000000..6e42dac
--- /dev/null
+++ b/media/libmedia/IAudioRecord.cpp
@@ -0,0 +1,100 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioRecord.h>
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ START,
+ STOP
+};
+
+class BpAudioRecord : public BpInterface<IAudioRecord>
+{
+public:
+ BpAudioRecord(const sp<IBinder>& impl)
+ : BpInterface<IAudioRecord>(impl)
+ {
+ }
+
+ virtual status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual sp<IMemory> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");
+
+// ----------------------------------------------------------------------
+
+#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 BnAudioRecord::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ reply->writeStrongBinder(getCblk()->asBinder());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
new file mode 100644
index 0000000..abc202d
--- /dev/null
+++ b/media/libmedia/IAudioTrack.cpp
@@ -0,0 +1,140 @@
+/* //device/extlibs/pv/android/IAudioTrack.cpp
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioTrack.h>
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ START,
+ STOP,
+ FLUSH,
+ MUTE,
+ PAUSE
+};
+
+class BpAudioTrack : public BpInterface<IAudioTrack>
+{
+public:
+ BpAudioTrack(const sp<IBinder>& impl)
+ : BpInterface<IAudioTrack>(impl)
+ {
+ }
+
+ virtual status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual void flush()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(FLUSH, data, &reply);
+ }
+
+ virtual void mute(bool e)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt32(e);
+ remote()->transact(MUTE, data, &reply);
+ }
+
+ virtual void pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual sp<IMemory> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
+
+// ----------------------------------------------------------------------
+
+#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 BnAudioTrack::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ reply->writeStrongBinder(getCblk()->asBinder());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ case FLUSH: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ flush();
+ return NO_ERROR;
+ } break;
+ case MUTE: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ mute( data.readInt32() );
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ pause();
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
new file mode 100644
index 0000000..85b5944
--- /dev/null
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -0,0 +1,218 @@
+/*
+**
+** Copyright (C) 2008 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+#include <SkBitmap.h>
+#include <media/IMediaMetadataRetriever.h>
+
+namespace android {
+
+enum {
+ DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ SET_DATA_SOURCE_URL,
+ SET_DATA_SOURCE_FD,
+ SET_MODE,
+ GET_MODE,
+ CAPTURE_FRAME,
+ EXTARCT_ALBUM_ART,
+ EXTRACT_METADATA,
+};
+
+class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
+{
+public:
+ BpMediaMetadataRetriever(const sp<IBinder>& impl)
+ : BpInterface<IMediaMetadataRetriever>(impl)
+ {
+ }
+
+ // disconnect from media metadata retriever service
+ void disconnect()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ remote()->transact(DISCONNECT, data, &reply);
+ }
+
+ status_t setDataSource(const char* srcUrl)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeCString(srcUrl);
+ remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setDataSource(int fd, int64_t offset, int64_t length)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setMode(int mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_MODE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getMode(int* mode) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ remote()->transact(GET_MODE, data, &reply);
+ *mode = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ sp<IMemory> captureFrame()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ remote()->transact(CAPTURE_FRAME, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return NULL;
+ }
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ sp<IMemory> extractAlbumArt()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ remote()->transact(EXTARCT_ALBUM_ART, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return NULL;
+ }
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ const char* extractMetadata(int keyCode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(keyCode);
+ remote()->transact(EXTRACT_METADATA, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return NULL;
+ }
+ return reply.readCString();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+
+// ----------------------------------------------------------------------
+
+#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 BnMediaMetadataRetriever::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case DISCONNECT: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ disconnect();
+ return NO_ERROR;
+ } break;
+ case SET_DATA_SOURCE_URL: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ const char* srcUrl = data.readCString();
+ reply->writeInt32(setDataSource(srcUrl));
+ return NO_ERROR;
+ } break;
+ case SET_DATA_SOURCE_FD: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ reply->writeInt32(setDataSource(fd, offset, length));
+ return NO_ERROR;
+ } break;
+ case SET_MODE: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int mode = data.readInt32();
+ reply->writeInt32(setMode(mode));
+ return NO_ERROR;
+ } break;
+ case GET_MODE: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int mode;
+ status_t status = getMode(&mode);
+ reply->writeInt32(mode);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
+ case CAPTURE_FRAME: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ sp<IMemory> bitmap = captureFrame();
+ if (bitmap != 0) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeStrongBinder(bitmap->asBinder());
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+ return NO_ERROR;
+ } break;
+ case EXTARCT_ALBUM_ART: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ sp<IMemory> albumArt = extractAlbumArt();
+ if (albumArt != 0) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeStrongBinder(albumArt->asBinder());
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+ return NO_ERROR;
+ } break;
+ case EXTRACT_METADATA: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int keyCode = data.readInt32();
+ const char* value = extractMetadata(keyCode);
+ if (value != NULL) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeCString(value);
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
new file mode 100644
index 0000000..f37519f
--- /dev/null
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -0,0 +1,275 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+enum {
+ DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ SET_VIDEO_SURFACE,
+ PREPARE_ASYNC,
+ START,
+ STOP,
+ IS_PLAYING,
+ PAUSE,
+ SEEK_TO,
+ GET_CURRENT_POSITION,
+ GET_DURATION,
+ RESET,
+ SET_AUDIO_STREAM_TYPE,
+ SET_LOOPING,
+ SET_VOLUME
+};
+
+class BpMediaPlayer: public BpInterface<IMediaPlayer>
+{
+public:
+ BpMediaPlayer(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayer>(impl)
+ {
+ }
+
+ // disconnect from media player service
+ void disconnect()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(DISCONNECT, data, &reply);
+ }
+
+ status_t setVideoSurface(const sp<ISurface>& surface)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeStrongBinder(surface->asBinder());
+ remote()->transact(SET_VIDEO_SURFACE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t prepareAsync()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(PREPARE_ASYNC, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t isPlaying(bool* state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(IS_PLAYING, data, &reply);
+ *state = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t seekTo(int msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(msec);
+ remote()->transact(SEEK_TO, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getCurrentPosition(int* msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_CURRENT_POSITION, data, &reply);
+ *msec = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t getDuration(int* msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_DURATION, data, &reply);
+ *msec = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t reset()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(RESET, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setAudioStreamType(int type)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(type);
+ remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setLooping(int loop)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(loop);
+ remote()->transact(SET_LOOPING, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setVolume(float leftVolume, float rightVolume)
+ {
+ Parcel data, reply;
+ data.writeFloat(leftVolume);
+ data.writeFloat(rightVolume);
+ remote()->transact(SET_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+
+// ----------------------------------------------------------------------
+
+#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 BnMediaPlayer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case DISCONNECT: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ disconnect();
+ return NO_ERROR;
+ } break;
+ case SET_VIDEO_SURFACE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ reply->writeInt32(setVideoSurface(surface));
+ return NO_ERROR;
+ } break;
+ case PREPARE_ASYNC: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(prepareAsync());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(stop());
+ return NO_ERROR;
+ } break;
+ case IS_PLAYING: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ bool state;
+ status_t ret = isPlaying(&state);
+ reply->writeInt32(state);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(pause());
+ return NO_ERROR;
+ } break;
+ case SEEK_TO: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(seekTo(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case GET_CURRENT_POSITION: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int msec;
+ status_t ret = getCurrentPosition(&msec);
+ reply->writeInt32(msec);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case GET_DURATION: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int msec;
+ status_t ret = getDuration(&msec);
+ reply->writeInt32(msec);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case RESET: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(reset());
+ return NO_ERROR;
+ } break;
+ case SET_AUDIO_STREAM_TYPE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setAudioStreamType(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_LOOPING: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setLooping(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_VOLUME: {
+ reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
new file mode 100644
index 0000000..65022cd
--- /dev/null
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayerClient.h>
+
+namespace android {
+
+enum {
+ NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
+{
+public:
+ BpMediaPlayerClient(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayerClient>(impl)
+ {
+ }
+
+ virtual void notify(int msg, int ext1, int ext2)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
+ data.writeInt32(msg);
+ data.writeInt32(ext1);
+ data.writeInt32(ext2);
+ remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+
+// ----------------------------------------------------------------------
+
+#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 BnMediaPlayerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case NOTIFY: {
+ CHECK_INTERFACE(IMediaPlayerClient, data, reply);
+ int msg = data.readInt32();
+ int ext1 = data.readInt32();
+ int ext2 = data.readInt32();
+ notify(msg, ext1, ext2);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
new file mode 100644
index 0000000..370e3fb
--- /dev/null
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -0,0 +1,198 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+
+#include <utils/IMemory.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+enum {
+ CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
+ CREATE_FD,
+ DECODE_URL,
+ DECODE_FD,
+ CREATE_MEDIA_RECORDER,
+ CREATE_METADATA_RETRIEVER,
+};
+
+class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
+{
+public:
+ BpMediaPlayerService(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayerService>(impl)
+ {
+ }
+
+ virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
+ return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeStrongBinder(client->asBinder());
+ data.writeCString(url);
+ remote()->transact(CREATE_URL, data, &reply);
+ return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
+ return interface_cast<IMediaRecorder>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeStrongBinder(client->asBinder());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(CREATE_FD, data, &reply);
+ return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeCString(url);
+ remote()->transact(DECODE_URL, data, &reply);
+ *pSampleRate = uint32_t(reply.readInt32());
+ *pNumChannels = reply.readInt32();
+ *pFormat = reply.readInt32();
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(DECODE_FD, data, &reply);
+ *pSampleRate = uint32_t(reply.readInt32());
+ *pNumChannels = reply.readInt32();
+ *pFormat = reply.readInt32();
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+
+// ----------------------------------------------------------------------
+
+#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 BnMediaPlayerService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CREATE_URL: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ const char* url = data.readCString();
+ sp<IMediaPlayer> player = create(pid, client, url);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case CREATE_FD: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ sp<IMediaPlayer> player = create(pid, client, fd, offset, length);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case DECODE_URL: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ const char* url = data.readCString();
+ uint32_t sampleRate;
+ int numChannels;
+ int format;
+ sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format);
+ reply->writeInt32(sampleRate);
+ reply->writeInt32(numChannels);
+ reply->writeInt32(format);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case DECODE_FD: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ uint32_t sampleRate;
+ int numChannels;
+ int format;
+ sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format);
+ reply->writeInt32(sampleRate);
+ reply->writeInt32(numChannels);
+ reply->writeInt32(format);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case CREATE_MEDIA_RECORDER: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaRecorder> recorder = createMediaRecorder(pid);
+ reply->writeStrongBinder(recorder->asBinder());
+ return NO_ERROR;
+ } break;
+ case CREATE_METADATA_RETRIEVER: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(pid);
+ reply->writeStrongBinder(retriever->asBinder());
+ 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
new file mode 100644
index 0000000..f187bf5
--- /dev/null
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -0,0 +1,417 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_NDEBUG 0
+#define LOG_TAG "IMediaRecorder"
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <ui/ISurface.h>
+#include <ui/ICamera.h>
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+enum {
+ RELEASE = IBinder::FIRST_CALL_TRANSACTION,
+ INIT,
+ CLOSE,
+ RESET,
+ STOP,
+ START,
+ PREPARE,
+ GET_MAX_AMPLITUDE,
+ SET_VIDEO_SOURCE,
+ SET_AUDIO_SOURCE,
+ SET_OUTPUT_FORMAT,
+ SET_VIDEO_ENCODER,
+ SET_AUDIO_ENCODER,
+ SET_OUTPUT_FILE_PATH,
+ SET_OUTPUT_FILE_FD,
+ SET_VIDEO_SIZE,
+ SET_VIDEO_FRAMERATE,
+ SET_PREVIEW_SURFACE,
+ SET_CAMERA,
+ SET_LISTENER
+};
+
+class BpMediaRecorder: public BpInterface<IMediaRecorder>
+{
+public:
+ BpMediaRecorder(const sp<IBinder>& impl)
+ : BpInterface<IMediaRecorder>(impl)
+ {
+ }
+
+ status_t setCamera(const sp<ICamera>& camera)
+ {
+ LOGV("setCamera(%p)", camera.get());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeStrongBinder(camera->asBinder());
+ remote()->transact(SET_CAMERA, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setPreviewSurface(const sp<ISurface>& surface)
+ {
+ LOGV("setPreviewSurface(%p)", surface.get());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeStrongBinder(surface->asBinder());
+ remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t init()
+ {
+ LOGV("init");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(INIT, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setVideoSource(int vs)
+ {
+ LOGV("setVideoSource(%d)", vs);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(vs);
+ remote()->transact(SET_VIDEO_SOURCE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setAudioSource(int as)
+ {
+ LOGV("setAudioSource(%d)", as);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(as);
+ remote()->transact(SET_AUDIO_SOURCE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setOutputFormat(int of)
+ {
+ LOGV("setOutputFormat(%d)", of);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(of);
+ remote()->transact(SET_OUTPUT_FORMAT, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setVideoEncoder(int ve)
+ {
+ LOGV("setVideoEncoder(%d)", ve);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(ve);
+ remote()->transact(SET_VIDEO_ENCODER, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setAudioEncoder(int ae)
+ {
+ LOGV("setAudioEncoder(%d)", ae);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(ae);
+ remote()->transact(SET_AUDIO_ENCODER, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setOutputFile(const char* path)
+ {
+ LOGV("setOutputFile(%s)", path);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeCString(path);
+ 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();
+ }
+
+ status_t setVideoSize(int width, int height)
+ {
+ LOGV("setVideoSize(%dx%d)", width, height);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(width);
+ data.writeInt32(height);
+ remote()->transact(SET_VIDEO_SIZE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setVideoFrameRate(int frames_per_second)
+ {
+ LOGV("setVideoFrameRate(%d)", frames_per_second);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(frames_per_second);
+ remote()->transact(SET_VIDEO_FRAMERATE, 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");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(PREPARE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getMaxAmplitude(int* max)
+ {
+ LOGV("getMaxAmplitude");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(GET_MAX_AMPLITUDE, data, &reply);
+ *max = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t start()
+ {
+ LOGV("start");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t stop()
+ {
+ LOGV("stop");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t reset()
+ {
+ LOGV("reset");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(RESET, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t close()
+ {
+ LOGV("close");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(CLOSE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t release()
+ {
+ LOGV("release");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(RELEASE, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+
+// ----------------------------------------------------------------------
+
+#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 BnMediaRecorder::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case RELEASE: {
+ LOGV("RELEASE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(release());
+ return NO_ERROR;
+ } break;
+ case INIT: {
+ LOGV("INIT");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(init());
+ return NO_ERROR;
+ } break;
+ case CLOSE: {
+ LOGV("CLOSE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(close());
+ return NO_ERROR;
+ } break;
+ case RESET: {
+ LOGV("RESET");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(reset());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ LOGV("STOP");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(stop());
+ return NO_ERROR;
+ } break;
+ case START: {
+ LOGV("START");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case PREPARE: {
+ LOGV("PREPARE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(prepare());
+ return NO_ERROR;
+ } break;
+ case GET_MAX_AMPLITUDE: {
+ LOGV("GET_MAX_AMPLITUDE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int max = 0;
+ status_t ret = getMaxAmplitude(&max);
+ reply->writeInt32(max);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case SET_VIDEO_SOURCE: {
+ LOGV("SET_VIDEO_SOURCE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int vs = data.readInt32();
+ reply->writeInt32(setVideoSource(vs));
+ return NO_ERROR;
+ } break;
+ case SET_AUDIO_SOURCE: {
+ LOGV("SET_AUDIO_SOURCE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int as = data.readInt32();
+ reply->writeInt32(setAudioSource(as));
+ return NO_ERROR;
+ } break;
+ case SET_OUTPUT_FORMAT: {
+ LOGV("SET_OUTPUT_FORMAT");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int of = data.readInt32();
+ reply->writeInt32(setOutputFormat(of));
+ return NO_ERROR;
+ } break;
+ case SET_VIDEO_ENCODER: {
+ LOGV("SET_VIDEO_ENCODER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int ve = data.readInt32();
+ reply->writeInt32(setVideoEncoder(ve));
+ return NO_ERROR;
+ } break;
+ case SET_AUDIO_ENCODER: {
+ LOGV("SET_AUDIO_ENCODER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int ae = data.readInt32();
+ reply->writeInt32(setAudioEncoder(ae));
+ return NO_ERROR;
+
+ } break;
+ 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);
+ int width = data.readInt32();
+ int height = data.readInt32();
+ reply->writeInt32(setVideoSize(width, height));
+ return NO_ERROR;
+ } break;
+ case SET_VIDEO_FRAMERATE: {
+ LOGV("SET_VIDEO_FRAMERATE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int frames_per_second = data.readInt32();
+ reply->writeInt32(setVideoFrameRate(frames_per_second));
+ 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);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ reply->writeInt32(setPreviewSurface(surface));
+ return NO_ERROR;
+ } break;
+ case SET_CAMERA: {
+ LOGV("SET_CAMERA");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ sp<ICamera> camera = interface_cast<ICamera>(data.readStrongBinder());
+ reply->writeInt32(setCamera(camera));
+ 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
new file mode 100644
index 0000000..2c62104
--- /dev/null
+++ b/media/libmedia/JetPlayer.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2008 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_NDEBUG 0
+#define LOG_TAG "JetPlayer-C"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <media/JetPlayer.h>
+
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+
+namespace android
+{
+
+static const int MIX_NUM_BUFFERS = 4;
+static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+ mEventCallback(NULL),
+ mJavaJetPlayerRef(javaJetPlayer),
+ mTid(-1),
+ mRender(false),
+ mPaused(false),
+ mMaxTracks(maxTracks),
+ mEasData(NULL),
+ mEasJetFileLoc(NULL),
+ mAudioTrack(NULL),
+ mTrackBufferSize(trackBufferSize)
+{
+ LOGV("JetPlayer constructor");
+ mPreviousJetStatus.currentUserID = -1;
+ mPreviousJetStatus.segmentRepeatCount = -1;
+ mPreviousJetStatus.numQueuedSegments = -1;
+ mPreviousJetStatus.paused = true;
+}
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::~JetPlayer()
+{
+ LOGV("~JetPlayer");
+ release();
+
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::init()
+{
+ //Mutex::Autolock lock(&mMutex);
+
+ EAS_RESULT result;
+
+ // retrieve the EAS library settings
+ if (pLibConfig == NULL)
+ pLibConfig = EAS_Config();
+ if (pLibConfig == NULL) {
+ LOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
+ return EAS_FAILURE;
+ }
+
+ // init the EAS library
+ result = EAS_Init(&mEasData);
+ if( result != EAS_SUCCESS) {
+ LOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
+ mState = EAS_STATE_ERROR;
+ return result;
+ }
+ // 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;
+ return result;
+ }
+
+ // create the output AudioTrack
+ mAudioTrack = new AudioTrack();
+ mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this
+ pLibConfig->sampleRate,
+ 1, // format = PCM 16bits per sample,
+ pLibConfig->numChannels,
+ mTrackBufferSize,
+ 0);
+
+ // create render and playback thread
+ {
+ Mutex::Autolock l(mMutex);
+ LOGV("JetPlayer::init(): trying to start render thread");
+ createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO);
+ mCondition.wait(mMutex);
+ }
+ if (mTid > 0) {
+ // render thread started, we're ready
+ LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
+ mState = EAS_STATE_READY;
+ } else {
+ LOGE("JetPlayer::init(): failed to start render thread.");
+ mState = EAS_STATE_ERROR;
+ return EAS_FAILURE;
+ }
+
+ return EAS_SUCCESS;
+}
+
+void JetPlayer::setEventCallback(jetevent_callback eventCallback)
+{
+ Mutex::Autolock l(mMutex);
+ mEventCallback = eventCallback;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::release()
+{
+ LOGV("JetPlayer::release()");
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ mRender = false;
+ if (mEasData) {
+ JET_Pause(mEasData);
+ JET_CloseFile(mEasData);
+ JET_Shutdown(mEasData);
+ EAS_Shutdown(mEasData);
+ }
+ if (mEasJetFileLoc) {
+ free(mEasJetFileLoc);
+ mEasJetFileLoc = NULL;
+ }
+ if (mAudioTrack) {
+ mAudioTrack->stop();
+ mAudioTrack->flush();
+ delete mAudioTrack;
+ mAudioTrack = NULL;
+ }
+ if (mAudioBuffer) {
+ delete mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mEasData = NULL;
+
+ return EAS_SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::renderThread(void* p) {
+
+ return ((JetPlayer*)p)->render();
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::render() {
+ EAS_RESULT result = EAS_FAILURE;
+ EAS_I32 count;
+ int temp;
+ bool audioStarted = false;
+
+ LOGV("JetPlayer::render(): entering");
+
+ // allocate render buffer
+ mAudioBuffer =
+ new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
+ if (!mAudioBuffer) {
+ LOGE("JetPlayer::render(): mAudioBuffer allocate failed");
+ goto threadExit;
+ }
+
+ // signal main thread that we started
+ {
+ Mutex::Autolock l(mMutex);
+ mTid = myTid();
+ LOGV("JetPlayer::render(): render thread(%d) signal", mTid);
+ mCondition.signal();
+ }
+
+ while (1) {
+ mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
+
+ // nothing to render, wait for client thread to wake us up
+ 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");
+ }
+
+ // render midi data into the input buffer
+ int num_output = 0;
+ EAS_PCM* p = mAudioBuffer;
+ for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
+ result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
+ if (result != EAS_SUCCESS) {
+ LOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
+ }
+ 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);
+ fireUpdateOnStatusChange();
+ mPaused = mJetStatus.paused;
+
+ mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
+
+ // check audio output track
+ if (mAudioTrack == NULL) {
+ LOGE("JetPlayer::render(): output AudioTrack was not created");
+ goto threadExit;
+ }
+
+ // Write data to the audio hardware
+ //LOGV("JetPlayer::render(): writing to audio output");
+ if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
+ LOGE("JetPlayer::render(): Error in writing:%d",temp);
+ return temp;
+ }
+
+ // start audio output if necessary
+ if (!audioStarted) {
+ LOGV("JetPlayer::render(): starting audio playback");
+ mAudioTrack->start();
+ audioStarted = true;
+ }
+
+ }//while (1)
+
+threadExit:
+ mAudioTrack->flush();
+ if (mAudioBuffer) {
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mMutex.lock();
+ mTid = -1;
+ mCondition.signal();
+ mMutex.unlock();
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up an update if any of the status fields has changed
+// precondition: mMutex locked
+void JetPlayer::fireUpdateOnStatusChange()
+{
+ if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
+ ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
+ if(mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_USERID_UPDATE,
+ mJetStatus.currentUserID,
+ mJetStatus.segmentRepeatCount,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
+ mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
+ }
+
+ if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
+ if(mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
+ mJetStatus.numQueuedSegments,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
+ }
+
+ if(mJetStatus.paused != mPreviousJetStatus.paused) {
+ if(mEventCallback) {
+ mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
+ mJetStatus.paused,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.paused = mJetStatus.paused;
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// 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::loadFromFile(): path=%s", path);
+
+ Mutex::Autolock lock(mMutex);
+
+ mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+ memset(mJetFilePath, 0, 256);
+ strncpy(mJetFilePath, path, strlen(path));
+ mEasJetFileLoc->path = mJetFilePath;
+
+ mEasJetFileLoc->fd = 0;
+ mEasJetFileLoc->length = 0;
+ mEasJetFileLoc->offset = 0;
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ if(result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ 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()
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_CloseFile(mEasData);
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::play()
+{
+ LOGV("JetPlayer::play(): entering");
+ Mutex::Autolock lock(mMutex);
+
+ EAS_RESULT result = JET_Play(mEasData);
+
+ mPaused = false;
+ mRender = true;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+
+ fireUpdateOnStatusChange();
+
+ // wake up render thread
+ LOGV("JetPlayer::play(): wakeup render thread");
+ mCondition.signal();
+
+ return result;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::pause()
+{
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ EAS_RESULT result = JET_Pause(mEasData);
+
+ mRender = false;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+ fireUpdateOnStatusChange();
+
+
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID)
+{
+ LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
+ segmentNum, libNum, repeatCount, transpose);
+ Mutex::Autolock lock(mMutex);
+ return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlags(mEasData, muteFlags, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::triggerClip(int clipId)
+{
+ LOGV("JetPlayer::triggerClip clipId=%d", clipId);
+ Mutex::Autolock lock(mMutex);
+ return JET_TriggerClip(mEasData, 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);
+}
+
+void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
+{
+ if(pJetStatus!=NULL)
+ LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
+ pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
+ pJetStatus->numQueuedSegments, pJetStatus->paused);
+ else
+ LOGE(">> JET player status is NULL");
+}
+
+
+} // end namespace android
+
diff --git a/media/libmedia/MODULE_LICENSE_APACHE2 b/media/libmedia/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/MODULE_LICENSE_APACHE2
diff --git a/media/libmedia/NOTICE b/media/libmedia/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libmedia/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
new file mode 100644
index 0000000..5416629
--- /dev/null
+++ b/media/libmedia/ToneGenerator.cpp
@@ -0,0 +1,730 @@
+/*
+ * Copyright (C) 2008 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_NDEBUG 0
+#define LOG_TAG "ToneGenerator"
+#include <utils/threads.h>
+
+#include <stdio.h>
+#include <math.h>
+#include <utils/Log.h>
+#include <sys/resource.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include "media/ToneGenerator.h"
+
+namespace android {
+
+// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
+const ToneGenerator::ToneDescriptor
+ ToneGenerator::toneDescriptors[NUM_TONES] = {
+ // waveFreq[] segments[] repeatCnt
+ { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0
+ { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1
+ { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2
+ { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3
+ { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4
+ { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5
+ { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6
+ { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7
+ { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8
+ { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9
+ { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S
+ { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P
+ { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A
+ { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B
+ { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C
+ { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D
+ { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL
+ { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY
+ { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION
+ { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK
+ { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL
+ { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
+ { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
+ { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
+ { { 400, 1200, 0 }, { 40, 0 }, 0 }, // TONE_PROP_BEEP
+ { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
+ { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
+ { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
+ { { 400, 1200, 0 }, { 40, 200, 40, 0 }, 0 } // TONE_PROP_BEEP2
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+// ToneGenerator class Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+
+//---------------------------------- public methods ----------------------------
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::ToneGenerator()
+//
+// Description: Constructor. Initializes the tone sequencer, intantiates required sine wave
+// generators, instantiates output audio track.
+//
+// Input:
+// toneType: Type of tone generated (values in enum tone_type)
+// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type)
+// volume: volume applied to tone (0.0 to 1.0)
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::ToneGenerator(int streamType, float volume) {
+
+ LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+
+ mState = TONE_IDLE;
+
+ if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
+ LOGE("Unable to marshal AudioFlinger");
+ return;
+ }
+ mStreamType = streamType;
+ mVolume = volume;
+ mpAudioTrack = 0;
+ mpToneDesc = 0;
+ mpNewToneDesc = 0;
+ // Generate tone by chunks of 20 ms to keep cadencing precision
+ mProcessSize = (mSamplingRate * 20) / 1000;
+
+ if (initAudioTrack()) {
+ LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+ } else {
+ LOGV("!!!ToneGenerator INIT FAILED!!!\n");
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::~ToneGenerator()
+//
+// Description: Destructor. Stop sound playback and delete audio track if
+// needed and delete sine wave generators.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::~ToneGenerator() {
+ LOGV("ToneGenerator destructor\n");
+
+ if (mpAudioTrack) {
+ stopTone();
+ LOGV("Delete Track: %p\n", mpAudioTrack);
+ delete mpAudioTrack;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::startTone()
+//
+// Description: Starts tone playback.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::startTone(int toneType) {
+ bool lResult = false;
+
+ if (toneType >= NUM_TONES)
+ return lResult;
+
+ if (mState == TONE_IDLE) {
+ LOGV("startTone: try to re-init AudioTrack");
+ if (!initAudioTrack()) {
+ return lResult;
+ }
+ }
+
+ LOGV("startTone\n");
+
+ mLock.lock();
+
+ // Get descriptor for requested tone
+ mpNewToneDesc = &toneDescriptors[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) {
+ LOGV("Wait for start callback");
+ if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
+ LOGE("--- Immediate start timed out");
+ mState = TONE_IDLE;
+ lResult = false;
+ }
+ }
+ } else {
+ mState == TONE_IDLE;
+ }
+ } else {
+ LOGV("Delayed start\n");
+
+ mState = TONE_RESTARTING;
+ if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
+ if (mState != TONE_IDLE) {
+ lResult = true;
+ }
+ LOGV("cond received");
+ } else {
+ LOGE("--- Delayed start timed out");
+ mState = TONE_IDLE;
+ }
+ }
+ mLock.unlock();
+
+ 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;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::stopTone()
+//
+// Description: Stops tone playback.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::stopTone() {
+ LOGV("stopTone");
+
+ mLock.lock();
+ if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
+ mState = TONE_STOPPING;
+ LOGV("waiting cond");
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus == NO_ERROR) {
+ LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
+ } else {
+ LOGE("--- Stop timed out");
+ mState = TONE_IDLE;
+ mpAudioTrack->stop();
+ }
+ }
+
+ clearWaveGens();
+
+ mLock.unlock();
+}
+
+//---------------------------------- private methods ---------------------------
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::initAudioTrack()
+//
+// Description: Allocates and configures AudioTrack used for PCM output.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::initAudioTrack() {
+
+ if (mpAudioTrack) {
+ delete mpAudioTrack;
+ mpAudioTrack = 0;
+ }
+
+ // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
+ mpAudioTrack
+ = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
+
+ if (mpAudioTrack == 0) {
+ LOGE("AudioTrack allocation failed");
+ goto initAudioTrack_exit;
+ }
+ LOGV("Create Track: %p\n", mpAudioTrack);
+
+ if (mpAudioTrack->initCheck() != NO_ERROR) {
+ LOGE("AudioTrack->initCheck failed");
+ goto initAudioTrack_exit;
+ }
+
+ mpAudioTrack->setVolume(mVolume, mVolume);
+
+ mState = TONE_INIT;
+
+ return true;
+
+initAudioTrack_exit:
+
+ // Cleanup
+ if (mpAudioTrack) {
+ LOGV("Delete Track I: %p\n", mpAudioTrack);
+ delete mpAudioTrack;
+ mpAudioTrack = 0;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::audioCallback()
+//
+// Description: AudioTrack callback implementation. Generates a block of
+// PCM samples
+// and manages tone generator sequencer: tones pulses, tone duration...
+//
+// Input:
+// user reference (pointer to our ToneGenerator)
+// info audio buffer descriptor
+//
+// Output:
+// returned value: always true.
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::audioCallback(int event, void* user, void *info) {
+
+ if (event != AudioTrack::EVENT_MORE_DATA) return;
+
+ const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
+ ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
+ short *lpOut = buffer->i16;
+ unsigned int lNumSmp = buffer->size/sizeof(short);
+
+ if (buffer->size == 0) return;
+
+
+ // Clear output buffer: WaveGenerator accumulates into lpOut buffer
+ memset(lpOut, 0, buffer->size);
+
+ while (lNumSmp) {
+ unsigned int lReqSmp = lNumSmp < lpToneGen->mProcessSize*2 ? lNumSmp : lpToneGen->mProcessSize;
+ unsigned int lGenSmp;
+ unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ bool lSignal = false;
+
+ lpToneGen->mLock.lock();
+
+ // Update pcm frame count and end time (current time at the end of this process)
+ lpToneGen->mTotalSmp += lReqSmp;
+
+ // Update tone gen state machine and select wave gen command
+ switch (lpToneGen->mState) {
+ case TONE_PLAYING:
+ lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ break;
+ case TONE_STARTING:
+ LOGV("Starting Cbk");
+
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+ break;
+ case TONE_STOPPING:
+ case TONE_RESTARTING:
+ LOGV("Stop/restart Cbk");
+
+ lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+ lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
+ break;
+ default:
+ LOGV("Extra Cbk");
+ goto audioCallback_EndLoop;
+ }
+
+
+ // Exit if tone sequence is over
+ if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+ if (lpToneGen->mState == TONE_PLAYING) {
+ lpToneGen->mState = TONE_STOPPING;
+ }
+ goto audioCallback_EndLoop;
+ }
+
+ if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
+ // Time to go to next sequence segment
+
+ LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ lGenSmp = lReqSmp;
+
+ if (lpToneGen->mCurSegment & 0x0001) {
+ // If odd segment, OFF -> ON transition : reset wave generator
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+ LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ } else {
+ // If even segment, ON -> OFF transition : ramp volume down
+ lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+
+ LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ }
+
+ // Pre increment segment index and handle loop if last segment reached
+ if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+ LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+
+ // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
+ if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+ LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+
+ lpToneGen->mCurSegment = 0;
+
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+
+ } else {
+ LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ // Cancel OFF->ON transition in case previous segment tone state was OFF
+ if (!(lpToneGen->mCurSegment & 0x0001)) {
+ lGenSmp = 0;
+ }
+ }
+ } else {
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+ }
+
+ // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
+ lpToneGen->mNextSegSmp
+ += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+
+ } else {
+ // Inside a segment keep tone ON or OFF
+ if (lpToneGen->mCurSegment & 0x0001) {
+ lGenSmp = 0; // If odd segment, tone is currently OFF
+ } else {
+ lGenSmp = lReqSmp; // If event segment, tone is currently ON
+ }
+ }
+
+ if (lGenSmp) {
+ // If samples must be generated, call all active wave generators and acumulate waves in lpOut
+ unsigned int lWaveIdx;
+
+ for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+ lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ }
+ }
+
+ lNumSmp -= lReqSmp;
+ lpOut += lReqSmp;
+
+audioCallback_EndLoop:
+
+ switch (lpToneGen->mState) {
+ case TONE_RESTARTING:
+ LOGV("Cbk restarting track\n");
+ if (lpToneGen->prepareWave()) {
+ lpToneGen->mState = TONE_STARTING;
+ } else {
+ LOGW("Cbk restarting prepareWave() failed\n");
+ lpToneGen->mState = TONE_IDLE;
+ lpToneGen->mpAudioTrack->stop();
+ // Force loop exit
+ lNumSmp = 0;
+ }
+ lSignal = true;
+ break;
+ case TONE_STOPPING:
+ lpToneGen->mState = TONE_INIT;
+ LOGV("Cbk Stopping track\n");
+ lSignal = true;
+ lpToneGen->mpAudioTrack->stop();
+
+ // Force loop exit
+ lNumSmp = 0;
+ break;
+ case TONE_STARTING:
+ LOGV("Cbk starting track\n");
+ lpToneGen->mState = TONE_PLAYING;
+ lSignal = true;
+ break;
+ default:
+ break;
+ }
+
+ if (lSignal)
+ lpToneGen->mWaitCbkCond.signal();
+ lpToneGen->mLock.unlock();
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::prepareWave()
+//
+// Description: Prepare wave generators and reset tone sequencer state machine.
+// mpNewToneDesc must have been initialized befoire calling this function.
+// Input:
+// none
+//
+// Output:
+// returned value: true if wave generators have been created, false otherwise
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::prepareWave() {
+ unsigned int lCnt = 0;
+ unsigned int lNumWaves;
+
+ if (!mpNewToneDesc) {
+ return false;
+ }
+ // Remove existing wave generators if any
+ clearWaveGens();
+
+ mpToneDesc = mpNewToneDesc;
+
+ // Get total number of sine waves: needed to adapt sine wave gain.
+ lNumWaves = numWaves();
+
+ // Instantiate as many wave generators as listed in descriptor
+ while (lCnt < lNumWaves) {
+ ToneGenerator::WaveGenerator *lpWaveGen =
+ new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+ mpToneDesc->waveFreq[lCnt],
+ TONEGEN_GAIN/lNumWaves);
+ if (lpWaveGen == 0) {
+ goto prepareWave_exit;
+ }
+
+ mWaveGens.push(lpWaveGen);
+ LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
+ lCnt++;
+ }
+
+ // Initialize tone sequencer
+ mTotalSmp = 0;
+ mCurSegment = 0;
+ mCurCount = 0;
+ mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+
+ return true;
+
+prepareWave_exit:
+
+ clearWaveGens();
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::numWaves()
+//
+// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+//
+// Input:
+// none
+//
+// Output:
+// returned value: nummber of sine waves
+//
+////////////////////////////////////////////////////////////////////////////////
+unsigned int ToneGenerator::numWaves() {
+ unsigned int lCnt = 0;
+
+ while (mpToneDesc->waveFreq[lCnt]) {
+ lCnt++;
+ }
+
+ return lCnt;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::clearWaveGens()
+//
+// Description: Removes all wave generators.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::clearWaveGens() {
+ LOGV("Clearing mWaveGens:");
+
+ while (!mWaveGens.isEmpty()) {
+ delete mWaveGens.top();
+ mWaveGens.pop();
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// WaveGenerator::WaveGenerator class Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+//---------------------------------- public methods ----------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::WaveGenerator()
+//
+// Description: Constructor.
+//
+// Input:
+// samplingRate: Output sampling rate in Hz
+// frequency: Frequency of the sine wave to generate in Hz
+// volume: volume (0.0 to 1.0)
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate,
+ unsigned short frequency, float volume) {
+ double d0;
+ double F_div_Fs; // frequency / samplingRate
+
+ F_div_Fs = frequency / (double)samplingRate;
+ d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
+ mS2_0 = (short)d0;
+ mS1 = 0;
+ mS2 = mS2_0;
+
+ mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
+ // take some margin for amplitude fluctuation
+ if (mAmplitude_Q15 > 32500)
+ mAmplitude_Q15 = 32500;
+
+ d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos()
+ if (d0 > 32767)
+ d0 = 32767;
+ mA1_Q14 = (short) d0;
+
+ LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+ mA1_Q14, mS2_0, mAmplitude_Q15);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::~WaveGenerator()
+//
+// Description: Destructor.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::~WaveGenerator() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::getSamples()
+//
+// Description: Generates count samples of a sine wave and accumulates
+// result in outBuffer.
+//
+// Input:
+// outBuffer: Output buffer where to accumulate samples.
+// count: number of samples to produce.
+// command: special action requested (see enum gen_command).
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
+ unsigned int count, unsigned int command) {
+ long lS1, lS2;
+ long lA1, lAmplitude;
+ long Sample; // current sample
+
+ // init local
+ if (command == WAVEGEN_START) {
+ lS1 = (long)0;
+ lS2 = (long)mS2_0;
+ } else {
+ lS1 = (long)mS1;
+ lS2 = (long)mS2;
+ }
+ lA1 = (long)mA1_Q14;
+ lAmplitude = (long)mAmplitude_Q15;
+
+ if (command == WAVEGEN_STOP) {
+ lAmplitude <<= 16;
+ if (count == 0) {
+ return;
+ }
+ long dec = lAmplitude/count;
+ // loop generation
+ while (count--) {
+ Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+ // shift delay
+ lS2 = lS1;
+ lS1 = Sample;
+ Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
+ *(outBuffer++) += (short)Sample; // put result in buffer
+ lAmplitude -= dec;
+ }
+ } else {
+ // loop generation
+ while (count--) {
+ Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+ // shift delay
+ lS2 = lS1;
+ lS1 = Sample;
+ Sample = (lAmplitude * Sample) >> S_Q15;
+ *(outBuffer++) += (short)Sample; // put result in buffer
+ }
+ }
+
+ // save status
+ mS1 = (short)lS1;
+ mS2 = (short)lS2;
+}
+
+} // end namespace android
+
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
new file mode 100644
index 0000000..09afc6c
--- /dev/null
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -0,0 +1,188 @@
+/*
+**
+** Copyright 2008, 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_NDEBUG 0
+#define LOG_TAG "MediaMetadataRetriever"
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <media/mediametadataretriever.h>
+#include <media/IMediaPlayerService.h>
+#include <utils/Log.h>
+#include <dlfcn.h>
+
+namespace android {
+
+// client singleton for binder interface to service
+Mutex MediaMetadataRetriever::sServiceLock;
+sp<IMediaPlayerService> MediaMetadataRetriever::sService;
+sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
+
+const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
+{
+ Mutex::Autolock lock(sServiceLock);
+ if (sService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.player"));
+ if (binder != 0) {
+ break;
+ }
+ LOGW("MediaPlayerService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (sDeathNotifier == NULL) {
+ sDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(sDeathNotifier);
+ sService = interface_cast<IMediaPlayerService>(binder);
+ }
+ LOGE_IF(sService == 0, "no MediaPlayerService!?");
+ return sService;
+}
+
+MediaMetadataRetriever::MediaMetadataRetriever()
+{
+ LOGV("constructor");
+ const sp<IMediaPlayerService>& service(getService());
+ if (service == 0) {
+ LOGE("failed to obtain MediaMetadataRetrieverService");
+ return;
+ }
+ sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid()));
+ if (retriever == 0) {
+ LOGE("failed to create IMediaMetadataRetriever object from server");
+ }
+ mRetriever = retriever;
+}
+
+MediaMetadataRetriever::~MediaMetadataRetriever()
+{
+ LOGV("destructor");
+ disconnect();
+ IPCThreadState::self()->flushCommands();
+}
+
+void MediaMetadataRetriever::disconnect()
+{
+ LOGV("disconnect");
+ sp<IMediaMetadataRetriever> retriever;
+ {
+ Mutex::Autolock _l(mLock);
+ retriever = mRetriever;
+ mRetriever.clear();
+ }
+ if (retriever != 0) {
+ retriever->disconnect();
+ }
+}
+
+status_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
+{
+ LOGV("setDataSource");
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+ if (srcUrl == NULL) {
+ LOGE("data source is a null pointer");
+ return UNKNOWN_ERROR;
+ }
+ LOGV("data source (%s)", srcUrl);
+ return mRetriever->setDataSource(srcUrl);
+}
+
+status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+ if (fd < 0 || offset < 0 || length < 0) {
+ LOGE("Invalid negative argument");
+ return UNKNOWN_ERROR;
+ }
+ return mRetriever->setDataSource(fd, offset, length);
+}
+
+status_t MediaMetadataRetriever::setMode(int mode)
+{
+ LOGV("setMode(%d)", mode);
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+ return mRetriever->setMode(mode);
+}
+
+status_t MediaMetadataRetriever::getMode(int* mode)
+{
+ LOGV("getMode");
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+ return mRetriever->getMode(mode);
+}
+
+sp<IMemory> MediaMetadataRetriever::captureFrame()
+{
+ LOGV("captureFrame");
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->captureFrame();
+}
+
+const char* MediaMetadataRetriever::extractMetadata(int keyCode)
+{
+ LOGV("extractMetadata(%d)", keyCode);
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->extractMetadata(keyCode);
+}
+
+sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
+{
+ LOGV("extractAlbumArt");
+ if (mRetriever == 0) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->extractAlbumArt();
+}
+
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
+ MediaMetadataRetriever::sService.clear();
+ LOGW("MediaMetadataRetriever server died!");
+}
+
+MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
+{
+ Mutex::Autolock lock(sServiceLock);
+ if (sService != 0) {
+ sService->asBinder()->unlinkToDeath(this);
+ }
+}
+
+}; // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
new file mode 100644
index 0000000..bd8579c
--- /dev/null
+++ b/media/libmedia/mediaplayer.cpp
@@ -0,0 +1,624 @@
+/* mediaplayer.cpp
+**
+** Copyright 2006, 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_NDEBUG 0
+#define LOG_TAG "MediaPlayer"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+
+#include <media/mediaplayer.h>
+#include <media/AudioTrack.h>
+
+#include <utils/MemoryBase.h>
+
+namespace android {
+
+// client singleton for binder interface to service
+Mutex MediaPlayer::sServiceLock;
+sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
+sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
+SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
+
+// establish binder interface to service
+const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
+{
+ Mutex::Autolock _l(sServiceLock);
+ if (sMediaPlayerService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.player"));
+ if (binder != 0)
+ break;
+ LOGW("MediaPlayerService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (sDeathNotifier == NULL) {
+ sDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(sDeathNotifier);
+ sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+ }
+ LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
+ return sMediaPlayerService;
+}
+
+void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
+{
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.add(recipient);
+}
+
+void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
+{
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.remove(recipient);
+}
+
+MediaPlayer::MediaPlayer()
+{
+ LOGV("constructor");
+ mListener = NULL;
+ mCookie = NULL;
+ mDuration = -1;
+ mStreamType = AudioSystem::MUSIC;
+ mCurrentPosition = -1;
+ mSeekPosition = -1;
+ mCurrentState = MEDIA_PLAYER_IDLE;
+ mPrepareSync = false;
+ mPrepareStatus = NO_ERROR;
+ mLoop = false;
+ mLeftVolume = mRightVolume = 1.0;
+ mVideoWidth = mVideoHeight = 0;
+}
+
+void MediaPlayer::onFirstRef()
+{
+ addObitRecipient(this);
+}
+
+MediaPlayer::~MediaPlayer()
+{
+ LOGV("destructor");
+ removeObitRecipient(this);
+ disconnect();
+ IPCThreadState::self()->flushCommands();
+}
+
+void MediaPlayer::disconnect()
+{
+ LOGV("disconnect");
+ sp<IMediaPlayer> p;
+ {
+ Mutex::Autolock _l(mLock);
+ p = mPlayer;
+ mPlayer.clear();
+ }
+
+ if (p != 0) {
+ p->disconnect();
+ }
+}
+
+// always call with lock held
+void MediaPlayer::clear_l()
+{
+ mDuration = -1;
+ mCurrentPosition = -1;
+ mSeekPosition = -1;
+ mVideoWidth = mVideoHeight = 0;
+}
+
+status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
+ return NO_ERROR;
+}
+
+
+status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
+{
+ status_t err = UNKNOWN_ERROR;
+ sp<IMediaPlayer> p;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+
+ if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
+ LOGE("setDataSource called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ clear_l();
+ p = mPlayer;
+ mPlayer = player;
+ if (player != 0) {
+ mCurrentState = MEDIA_PLAYER_INITIALIZED;
+ err = NO_ERROR;
+ } else {
+ LOGE("Unable to to create media player");
+ }
+ }
+
+ if (p != 0) {
+ p->disconnect();
+ }
+
+ return err;
+}
+
+status_t MediaPlayer::setDataSource(const char *url)
+{
+ LOGV("setDataSource(%s)", url);
+ status_t err = BAD_VALUE;
+ if (url != NULL) {
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
+ if (service != 0) {
+ sp<IMediaPlayer> player(service->create(getpid(), this, url));
+ err = setDataSource(player);
+ }
+ }
+ return err;
+}
+
+status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+ status_t err = UNKNOWN_ERROR;
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
+ if (service != 0) {
+ sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
+ err = setDataSource(player);
+ }
+ return err;
+}
+
+status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
+{
+ LOGV("setVideoSurface");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return NO_INIT;
+ return mPlayer->setVideoSurface(surface->getISurface());
+}
+
+// must call with lock held
+status_t MediaPlayer::prepareAsync_l()
+{
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
+ mPlayer->setAudioStreamType(mStreamType);
+ mCurrentState = MEDIA_PLAYER_PREPARING;
+ return mPlayer->prepareAsync();
+ }
+ LOGE("prepareAsync called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::prepare()
+{
+ LOGV("prepare");
+ Mutex::Autolock _l(mLock);
+ if (mPrepareSync) return -EALREADY;
+ mPrepareSync = true;
+ status_t ret = prepareAsync_l();
+ if (ret != NO_ERROR) return ret;
+
+ if (mPrepareSync) {
+ mSignal.wait(mLock); // wait for prepare done
+ mPrepareSync = false;
+ }
+ LOGV("prepare complete - status=%d", mPrepareStatus);
+ return mPrepareStatus;
+}
+
+status_t MediaPlayer::prepareAsync()
+{
+ LOGV("prepareAsync");
+ Mutex::Autolock _l(mLock);
+ return prepareAsync_l();
+}
+
+status_t MediaPlayer::start()
+{
+ LOGV("start");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_STARTED)
+ return NO_ERROR;
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
+ MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
+ mPlayer->setLooping(mLoop);
+ mPlayer->setVolume(mLeftVolume, mRightVolume);
+ mCurrentState = MEDIA_PLAYER_STARTED;
+ status_t ret = mPlayer->start();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ } else {
+ if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
+ LOGV("playback completed immediately following start()");
+ }
+ }
+ return ret;
+ }
+ LOGE("start called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::stop()
+{
+ LOGV("stop");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
+ status_t ret = mPlayer->stop();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_STOPPED;
+ }
+ return ret;
+ }
+ LOGE("stop called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::pause()
+{
+ LOGV("pause");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_PAUSED)
+ return NO_ERROR;
+ if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
+ status_t ret = mPlayer->pause();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_PAUSED;
+ }
+ return ret;
+ }
+ LOGE("pause called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+bool MediaPlayer::isPlaying()
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ bool temp = false;
+ mPlayer->isPlaying(&temp);
+ LOGV("isPlaying: %d", temp);
+ if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
+ LOGE("internal/external state mismatch corrected");
+ mCurrentState = MEDIA_PLAYER_PAUSED;
+ }
+ return temp;
+ }
+ LOGV("isPlaying: no active player");
+ return false;
+}
+
+status_t MediaPlayer::getVideoWidth(int *w)
+{
+ LOGV("getVideoWidth");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return INVALID_OPERATION;
+ *w = mVideoWidth;
+ return NO_ERROR;
+}
+
+status_t MediaPlayer::getVideoHeight(int *h)
+{
+ LOGV("getVideoHeight");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return INVALID_OPERATION;
+ *h = mVideoHeight;
+ return NO_ERROR;
+}
+
+status_t MediaPlayer::getCurrentPosition(int *msec)
+{
+ LOGV("getCurrentPosition");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ if (mCurrentPosition >= 0) {
+ LOGV("Using cached seek position: %d", mCurrentPosition);
+ *msec = mCurrentPosition;
+ return NO_ERROR;
+ }
+ return mPlayer->getCurrentPosition(msec);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration_l(int *msec)
+{
+ LOGV("getDuration");
+ bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
+ if (mPlayer != 0 && isValidState) {
+ status_t ret = NO_ERROR;
+ if (mDuration <= 0)
+ ret = mPlayer->getDuration(&mDuration);
+ if (msec)
+ *msec = mDuration;
+ return ret;
+ }
+ LOGE("Attempt to call getDuration without a valid mediaplayer");
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration(int *msec)
+{
+ Mutex::Autolock _l(mLock);
+ return getDuration_l(msec);
+}
+
+status_t MediaPlayer::seekTo_l(int msec)
+{
+ LOGV("seekTo %d", msec);
+ if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
+ if ( msec < 0 ) {
+ LOGW("Attempt to seek to invalid position: %d", msec);
+ msec = 0;
+ } else if ((mDuration > 0) && (msec > mDuration)) {
+ LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
+ msec = mDuration;
+ }
+ // cache duration
+ mCurrentPosition = msec;
+ if (mSeekPosition < 0) {
+ getDuration_l(NULL);
+ mSeekPosition = msec;
+ return mPlayer->seekTo(msec);
+ }
+ else {
+ LOGV("Seek in progress - queue up seekTo[%d]", msec);
+ return NO_ERROR;
+ }
+ }
+ LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::seekTo(int msec)
+{
+ Mutex::Autolock _l(mLock);
+ return seekTo_l(msec);
+}
+
+status_t MediaPlayer::reset()
+{
+ LOGV("reset");
+ Mutex::Autolock _l(mLock);
+ mLoop = false;
+ if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
+ mPrepareSync = false;
+ if (mPlayer != 0) {
+ status_t ret = mPlayer->reset();
+ if (ret != NO_ERROR) {
+ LOGE("reset() failed with return code (%d)", ret);
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_IDLE;
+ }
+ return ret;
+ }
+ clear_l();
+ return NO_ERROR;
+}
+
+status_t MediaPlayer::setAudioStreamType(int type)
+{
+ LOGV("MediaPlayer::setAudioStreamType");
+ Mutex::Autolock _l(mLock);
+ if (mStreamType == type) return NO_ERROR;
+ if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
+ // Can't change the stream type after prepare
+ LOGE("setAudioStream called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+ // cache
+ mStreamType = type;
+ return OK;
+}
+
+status_t MediaPlayer::setLooping(int loop)
+{
+ LOGV("MediaPlayer::setLooping");
+ Mutex::Autolock _l(mLock);
+ mLoop = (loop != 0);
+ if (mPlayer != 0) {
+ return mPlayer->setLooping(loop);
+ }
+ return OK;
+}
+
+bool MediaPlayer::isLooping() {
+ LOGV("isLooping");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ return mLoop;
+ }
+ LOGV("isLooping: no active player");
+ return false;
+}
+
+status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
+{
+ LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
+ Mutex::Autolock _l(mLock);
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ if (mPlayer != 0) {
+ return mPlayer->setVolume(leftVolume, rightVolume);
+ }
+ return OK;
+}
+
+void MediaPlayer::notify(int msg, int ext1, int ext2)
+{
+ LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+ bool send = true;
+
+ // TODO: In the future, we might be on the same thread if the app is
+ // running in the same process as the media server. In that case,
+ // this will deadlock.
+ mLock.lock();
+ if (mPlayer == 0) {
+ LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+ mLock.unlock(); // release the lock when done.
+ return;
+ }
+
+ switch (msg) {
+ case MEDIA_NOP: // interface test message
+ break;
+ case MEDIA_PREPARED:
+ LOGV("prepared");
+ mCurrentState = MEDIA_PLAYER_PREPARED;
+ if (mPrepareSync) {
+ LOGV("signal application thread");
+ mPrepareSync = false;
+ mPrepareStatus = NO_ERROR;
+ mSignal.signal();
+ }
+ break;
+ case MEDIA_PLAYBACK_COMPLETE:
+ LOGV("playback complete");
+ if (!mLoop) {
+ mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
+ }
+ break;
+ case MEDIA_ERROR:
+ // Always log errors
+ LOGE("error (%d, %d)", ext1, ext2);
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ if (mPrepareSync)
+ {
+ LOGV("signal application thread");
+ mPrepareSync = false;
+ mPrepareStatus = ext1;
+ mSignal.signal();
+ send = false;
+ }
+ break;
+ case MEDIA_SEEK_COMPLETE:
+ LOGV("Received seek complete");
+ if (mSeekPosition != mCurrentPosition) {
+ LOGV("Executing queued seekTo(%d)", mSeekPosition);
+ mSeekPosition = -1;
+ seekTo_l(mCurrentPosition);
+ }
+ else {
+ LOGV("All seeks complete - return to regularly scheduled program");
+ mCurrentPosition = mSeekPosition = -1;
+ }
+ break;
+ case MEDIA_BUFFERING_UPDATE:
+ LOGV("buffering %d", ext1);
+ break;
+ case MEDIA_SET_VIDEO_SIZE:
+ LOGV("New video size %d x %d", ext1, ext2);
+ mVideoWidth = ext1;
+ mVideoHeight = ext2;
+ break;
+ default:
+ LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
+ break;
+ }
+
+ sp<MediaPlayerListener> listener = mListener;
+ mLock.unlock();
+
+ // this prevents re-entrant calls into client code
+ if ((listener != 0) && send) {
+ Mutex::Autolock _l(mNotifyLock);
+ LOGV("callback application");
+ listener->notify(msg, ext1, ext2);
+ LOGV("back from callback");
+ }
+}
+
+void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ LOGW("MediaPlayer server died!");
+
+ // Need to do this with the lock held
+ SortedVector< wp<MediaPlayer> > list;
+ {
+ Mutex::Autolock _l(MediaPlayer::sServiceLock);
+ MediaPlayer::sMediaPlayerService.clear();
+ list = sObitRecipients;
+ }
+
+ // Notify application when media server dies.
+ // Don't hold the static lock during callback in case app
+ // makes a call that needs the lock.
+ size_t count = list.size();
+ for (size_t iter = 0; iter < count; ++iter) {
+ sp<MediaPlayer> player = list[iter].promote();
+ if ((player != 0) && (player->mPlayer != 0)) {
+ player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+ }
+ }
+}
+
+MediaPlayer::DeathNotifier::~DeathNotifier()
+{
+ Mutex::Autolock _l(sServiceLock);
+ sObitRecipients.clear();
+ if (sMediaPlayerService != 0) {
+ sMediaPlayerService->asBinder()->unlinkToDeath(this);
+ }
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+ LOGV("decode(%s)", url);
+ sp<IMemory> p;
+ const sp<IMediaPlayerService>& service = getMediaPlayerService();
+ if (service != 0) {
+ p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
+ } else {
+ LOGE("Unable to locate media service");
+ }
+ return p;
+
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+ LOGV("decode(%d, %lld, %lld)", fd, offset, length);
+ sp<IMemory> p;
+ const sp<IMediaPlayerService>& service = getMediaPlayerService();
+ if (service != 0) {
+ p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
+ } else {
+ LOGE("Unable to locate media service");
+ }
+ return p;
+
+}
+
+}; // namespace android
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
new file mode 100644
index 0000000..98aac39
--- /dev/null
+++ b/media/libmedia/mediarecorder.cpp
@@ -0,0 +1,617 @@
+/*
+ **
+ ** Copyright (c) 2008 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_NDEBUG 0
+#define LOG_TAG "MediaRecorder"
+#include <utils/Log.h>
+#include <ui/Surface.h>
+#include <media/mediarecorder.h>
+#include <utils/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
+{
+ LOGV("setCamera(%p)", camera.get());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+ LOGE("setCamera called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setCamera(camera);
+ if (OK != ret) {
+ LOGV("setCamera failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ return ret;
+}
+
+status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
+{
+ LOGV("setPreviewSurface(%p)", surface.get());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ 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;
+}
+
+status_t MediaRecorder::init()
+{
+ LOGV("init");
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+ LOGE("init called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->init();
+ if (OK != ret) {
+ LOGV("init failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+
+ ret = mMediaRecorder->setListener(this);
+ if (OK != ret) {
+ LOGV("setListener failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+
+ mCurrentState = MEDIA_RECORDER_INITIALIZED;
+ return ret;
+}
+
+status_t MediaRecorder::setVideoSource(int vs)
+{
+ LOGV("setVideoSource(%d)", vs);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (mIsVideoSourceSet) {
+ LOGE("video source has already been set");
+ return INVALID_OPERATION;
+ }
+ if (mCurrentState & MEDIA_RECORDER_IDLE) {
+ LOGV("Call init() since the media recorder is not initialized yet");
+ status_t ret = init();
+ if (OK != ret) {
+ return ret;
+ }
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+ LOGE("setVideoSource called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setVideoSource(vs);
+ if (OK != ret) {
+ LOGV("setVideoSource failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsVideoSourceSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setAudioSource(int as)
+{
+ LOGV("setAudioSource(%d)", as);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (mCurrentState & MEDIA_RECORDER_IDLE) {
+ LOGV("Call init() since the media recorder is not initialized yet");
+ status_t ret = init();
+ if (OK != ret) {
+ return ret;
+ }
+ }
+ if (mIsAudioSourceSet) {
+ LOGE("audio source has already been set");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+ LOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setAudioSource(as);
+ if (OK != ret) {
+ LOGV("setAudioSource failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsAudioSourceSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setOutputFormat(int of)
+{
+ LOGV("setOutputFormat(%d)", of);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+ 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;
+ }
+ mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
+ return ret;
+}
+
+status_t MediaRecorder::setVideoEncoder(int ve)
+{
+ LOGV("setVideoEncoder(%d)", ve);
+ if(mMediaRecorder == NULL) {
+ 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;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ LOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setVideoEncoder(ve);
+ if (OK != ret) {
+ LOGV("setVideoEncoder failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsVideoEncoderSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setAudioEncoder(int ae)
+{
+ LOGV("setAudioEncoder(%d)", ae);
+ if(mMediaRecorder == NULL) {
+ 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;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ LOGE("setAudioEncoder called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setAudioEncoder(ae);
+ if (OK != ret) {
+ LOGV("setAudioEncoder failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsAudioEncoderSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setOutputFile(const char* path)
+{
+ LOGV("setOutputFile(%s)", path);
+ 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(path);
+ if (OK != ret) {
+ LOGV("setOutputFile failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsOutputFileSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (mIsOutputFileSet) {
+ LOGE("output file has already been set");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+ if (OK != ret) {
+ LOGV("setOutputFile failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mIsOutputFileSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setVideoSize(int width, int height)
+{
+ LOGV("setVideoSize(%d, %d)", width, height);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ 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;
+}
+
+status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
+{
+ LOGV("setVideoFrameRate(%d)", frames_per_second);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ 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;
+}
+
+status_t MediaRecorder::prepare()
+{
+ LOGV("prepare");
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ 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;
+ }
+
+ status_t ret = mMediaRecorder->prepare();
+ if (OK != ret) {
+ LOGE("prepare failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mCurrentState = MEDIA_RECORDER_PREPARED;
+ return ret;
+}
+
+status_t MediaRecorder::getMaxAmplitude(int* max)
+{
+ LOGV("getMaxAmplitude");
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (mCurrentState & MEDIA_RECORDER_ERROR) {
+ LOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->getMaxAmplitude(max);
+ if (OK != ret) {
+ LOGE("getMaxAmplitude failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ return ret;
+}
+
+status_t MediaRecorder::start()
+{
+ LOGV("start");
+ if (mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) {
+ LOGE("start called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->start();
+ if (OK != ret) {
+ LOGE("start failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mCurrentState = MEDIA_RECORDER_RECORDING;
+ return ret;
+}
+
+status_t MediaRecorder::stop()
+{
+ LOGV("stop");
+ if (mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+ LOGE("stop called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->stop();
+ if (OK != ret) {
+ LOGE("stop failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ }
+ mCurrentState = MEDIA_RECORDER_IDLE;
+ return ret;
+}
+
+// Reset should be OK in any state
+status_t MediaRecorder::reset()
+{
+ LOGV("reset");
+ if (mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ doCleanUp();
+ status_t ret = UNKNOWN_ERROR;
+ switch(mCurrentState) {
+ case MEDIA_RECORDER_IDLE:
+ ret = OK;
+ break;
+
+ case MEDIA_RECORDER_RECORDING:
+ case MEDIA_RECORDER_DATASOURCE_CONFIGURED:
+ case MEDIA_RECORDER_PREPARED:
+ case MEDIA_RECORDER_ERROR: {
+ ret = doReset();
+ if (OK != ret) {
+ return ret; // No need to continue
+ }
+ } // Intentional fall through
+ case MEDIA_RECORDER_INITIALIZED:
+ ret = close();
+ break;
+
+ default: {
+ LOGE("Unexpected non-existing state: %d", mCurrentState);
+ break;
+ }
+ }
+ return ret;
+}
+
+status_t MediaRecorder::close()
+{
+ LOGV("close");
+ if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+ LOGE("close called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+ status_t ret = mMediaRecorder->close();
+ if (OK != ret) {
+ LOGE("close failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ } else {
+ mCurrentState = MEDIA_RECORDER_IDLE;
+ }
+ return ret;
+}
+
+status_t MediaRecorder::doReset()
+{
+ LOGV("doReset");
+ status_t ret = mMediaRecorder->reset();
+ if (OK != ret) {
+ LOGE("doReset failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return UNKNOWN_ERROR;
+ } else {
+ mCurrentState = MEDIA_RECORDER_INITIALIZED;
+ }
+ return ret;
+}
+
+void MediaRecorder::doCleanUp()
+{
+ LOGV("doCleanUp");
+ mIsAudioSourceSet = false;
+ mIsVideoSourceSet = false;
+ mIsAudioEncoderSet = false;
+ mIsVideoEncoderSet = false;
+ mIsOutputFileSet = false;
+}
+
+// Release should be OK in any state
+status_t MediaRecorder::release()
+{
+ LOGV("release");
+ if (mMediaRecorder != NULL) {
+ return mMediaRecorder->release();
+ }
+ return INVALID_OPERATION;
+}
+
+MediaRecorder::MediaRecorder()
+{
+ LOGV("constructor");
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+
+ do {
+ binder = sm->getService(String16("media.player"));
+ if (binder != NULL) {
+ break;
+ }
+ LOGW("MediaPlayerService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ if (service != NULL) {
+ mMediaRecorder = service->createMediaRecorder(getpid());
+ }
+ if (mMediaRecorder != NULL) {
+ mCurrentState = MEDIA_RECORDER_IDLE;
+ }
+ doCleanUp();
+}
+
+status_t MediaRecorder::initCheck()
+{
+ return mMediaRecorder != 0 ? NO_ERROR : NO_INIT;
+}
+
+MediaRecorder::~MediaRecorder()
+{
+ LOGV("destructor");
+ if (mMediaRecorder != NULL) {
+ mMediaRecorder.clear();
+ }
+}
+
+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/Android.mk b/media/libmediaplayerservice/Android.mk
new file mode 100644
index 0000000..f710921
--- /dev/null
+++ b/media/libmediaplayerservice/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# libmediaplayerservice
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ MediaRecorderClient.cpp \
+ MediaPlayerService.cpp \
+ MetadataRetrieverClient.cpp \
+ VorbisPlayer.cpp \
+ MidiFile.cpp
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl -lpthread
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libvorbisidec \
+ libsonivox \
+ libopencoreplayer \
+ libopencoreauthor \
+ libmedia \
+ libandroid_runtime
+
+LOCAL_C_INCLUDES := external/tremor/Tremor \
+ $(call include-path-for, graphics corecg)
+
+LOCAL_MODULE:= libmediaplayerservice
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
new file mode 100644
index 0000000..40705c6
--- /dev/null
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -0,0 +1,1173 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+// Proxy for media player implementations
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayerService"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <cutils/atomic.h>
+
+#include <android_runtime/ActivityManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/MemoryBase.h>
+#include <cutils/properties.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/mediarecorder.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/AudioTrack.h>
+
+#include "MediaRecorderClient.h"
+#include "MediaPlayerService.h"
+#include "MetadataRetrieverClient.h"
+
+#include "MidiFile.h"
+#include "VorbisPlayer.h"
+#include <media/PVPlayer.h>
+
+/* desktop Linux needs a little help with gettid() */
+#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
+#define __KERNEL__
+# include <linux/unistd.h>
+#ifdef _syscall0
+_syscall0(pid_t,gettid)
+#else
+pid_t gettid() { return syscall(__NR_gettid);}
+#endif
+#undef __KERNEL__
+#endif
+
+
+namespace android {
+
+// TODO: Temp hack until we can register players
+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},
+};
+
+// 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;
+
+void MediaPlayerService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.player"), new MediaPlayerService());
+}
+
+MediaPlayerService::MediaPlayerService()
+{
+ LOGV("MediaPlayerService created");
+ mNextConnId = 1;
+}
+
+MediaPlayerService::~MediaPlayerService()
+{
+ LOGV("MediaPlayerService destroyed");
+}
+
+sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
+{
+ sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+ LOGV("Create new media recorder client from pid %d", pid);
+ return recorder;
+}
+
+sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid)
+{
+ sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
+ LOGV("Create new media retriever from pid %d", pid);
+ return retriever;
+}
+
+sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
+{
+ int32_t connId = android_atomic_inc(&mNextConnId);
+ sp<Client> c = new Client(this, pid, connId, client);
+ LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
+ if (NO_ERROR != c->setDataSource(url))
+ {
+ c.clear();
+ return c;
+ }
+ wp<Client> w = c;
+ Mutex::Autolock lock(mLock);
+ mClients.add(w);
+ return c;
+}
+
+sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
+ int fd, int64_t offset, int64_t length)
+{
+ int32_t connId = android_atomic_inc(&mNextConnId);
+ sp<Client> c = new Client(this, pid, connId, client);
+ LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld",
+ connId, pid, fd, offset, length);
+ if (NO_ERROR != c->setDataSource(fd, offset, length)) {
+ c.clear();
+ } else {
+ wp<Client> w = c;
+ Mutex::Autolock lock(mLock);
+ mClients.add(w);
+ }
+ ::close(fd);
+ return c;
+}
+
+status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append(" AudioCache\n");
+ if (mHeap != 0) {
+ snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n",
+ mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
+ result.append(buffer);
+ }
+ snprintf(buffer, 255, " msec per frame(%f), channel count(%d), format(%d), frame count(%ld)\n",
+ mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
+ result.append(buffer);
+ snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n",
+ mSampleRate, mSize, mError, mCommandComplete?"true":"false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append(" AudioOutput\n");
+ snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
+ mStreamType, mLeftVolume, mRightVolume);
+ result.append(buffer);
+ snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
+ mMsecsPerFrame, mLatency);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ if (mTrack != 0) {
+ mTrack->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append(" Client\n");
+ snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
+ mPid, mConnId, mStatus, mLoop?"true": "false");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mAudioOutput != 0) {
+ mAudioOutput->dump(fd, args);
+ }
+ write(fd, "\n", 1);
+ return NO_ERROR;
+}
+
+static int myTid() {
+#ifdef HAVE_GETTID
+ return gettid();
+#else
+ return getpid();
+#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;
+ char buffer[SIZE];
+ String8 result;
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump MediaPlayerService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ } else {
+ Mutex::Autolock lock(mLock);
+ for (int i = 0, n = mClients.size(); i < n; ++i) {
+ sp<Client> c = mClients[i].promote();
+ if (c != 0) c->dump(fd, args);
+ }
+ result.append(" Files opened and/or mapped:\n");
+ snprintf(buffer, SIZE, "/proc/%d/maps", myTid());
+ FILE *f = fopen(buffer, "r");
+ if (f) {
+ while (!feof(f)) {
+ fgets(buffer, SIZE, f);
+ if (strstr(buffer, " /sdcard/") ||
+ strstr(buffer, " /system/sounds/") ||
+ strstr(buffer, " /system/media/")) {
+ result.append(" ");
+ result.append(buffer);
+ }
+ }
+ fclose(f);
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ result.append("\n");
+ }
+
+ snprintf(buffer, SIZE, "/proc/%d/fd", myTid());
+ DIR *d = opendir(buffer);
+ if (d) {
+ struct dirent *ent;
+ while((ent = readdir(d)) != NULL) {
+ if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
+ snprintf(buffer, SIZE, "/proc/%d/fd/%s", myTid(), ent->d_name);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ if (strstr(linkto, "/sdcard/") == linkto ||
+ strstr(linkto, "/system/sounds/") == linkto ||
+ strstr(linkto, "/system/media/") == linkto) {
+ result.append(" ");
+ result.append(buffer);
+ result.append(" -> ");
+ result.append(linkto);
+ result.append("\n");
+ }
+ }
+ } else {
+ result.append(" unexpected type for ");
+ result.append(buffer);
+ result.append("\n");
+ }
+ }
+ }
+ }
+ closedir(d);
+ } else {
+ result.append("couldn't open ");
+ 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;
+}
+
+void MediaPlayerService::removeClient(wp<Client> client)
+{
+ Mutex::Autolock lock(mLock);
+ mClients.remove(client);
+}
+
+MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid,
+ int32_t connId, const sp<IMediaPlayerClient>& client)
+{
+ LOGV("Client(%d) constructor", connId);
+ mPid = pid;
+ mConnId = connId;
+ mService = service;
+ mClient = client;
+ mLoop = false;
+ mStatus = NO_INIT;
+#if CALLBACK_ANTAGONIZER
+ LOGD("create Antagonizer");
+ mAntagonizer = new Antagonizer(notify, this);
+#endif
+}
+
+MediaPlayerService::Client::~Client()
+{
+ LOGV("Client(%d) destructor pid = %d", mConnId, mPid);
+ mAudioOutput.clear();
+ wp<Client> client(this);
+ disconnect();
+ mService->removeClient(client);
+}
+
+void MediaPlayerService::Client::disconnect()
+{
+ LOGV("disconnect(%d) from pid %d", mConnId, mPid);
+ // grab local reference and clear main reference to prevent future
+ // access to object
+ sp<MediaPlayerBase> p;
+ {
+ Mutex::Autolock l(mLock);
+ p = mPlayer;
+ }
+ mPlayer.clear();
+
+ // clear the notification to prevent callbacks to dead client
+ // and reset the player. We assume the player will serialize
+ // access to itself if necessary.
+ if (p != 0) {
+ p->setNotifyCallback(0, 0);
+#if CALLBACK_ANTAGONIZER
+ LOGD("kill Antagonizer");
+ mAntagonizer->kill();
+#endif
+ p->reset();
+ }
+
+ IPCThreadState::self()->flushCommands();
+}
+
+static player_type getPlayerType(int fd, int64_t offset, int64_t length)
+{
+ char buf[20];
+ lseek(fd, offset, SEEK_SET);
+ read(fd, buf, sizeof(buf));
+ lseek(fd, offset, SEEK_SET);
+
+ long ident = *((long*)buf);
+
+ // Ogg vorbis?
+ if (ident == 0x5367674f) // 'OggS'
+ return VORBIS_PLAYER;
+
+ // Some kind of MIDI?
+ EAS_DATA_HANDLE easdata;
+ if (EAS_Init(&easdata) == EAS_SUCCESS) {
+ EAS_FILE locator;
+ locator.path = NULL;
+ locator.fd = fd;
+ locator.offset = offset;
+ locator.length = length;
+ EAS_HANDLE eashandle;
+ if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
+ EAS_CloseFile(easdata, eashandle);
+ EAS_Shutdown(easdata);
+ return SONIVOX_PLAYER;
+ }
+ EAS_Shutdown(easdata);
+ }
+
+ // Fall through to PV
+ return PV_PLAYER;
+}
+
+static player_type getPlayerType(const char* url)
+{
+
+ // use MidiFile for MIDI extensions
+ int lenURL = strlen(url);
+ 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, FILE_EXTS[i].extension, len)) {
+ return FILE_EXTS[i].playertype;
+ }
+ }
+ }
+
+ // Fall through to PV
+ return PV_PLAYER;
+}
+
+static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
+ notify_callback_f notifyFunc)
+{
+ sp<MediaPlayerBase> p;
+ switch (playerType) {
+ case PV_PLAYER:
+ LOGV(" create PVPlayer");
+ p = new PVPlayer();
+ break;
+ case SONIVOX_PLAYER:
+ LOGV(" create MidiFile");
+ p = new MidiFile();
+ break;
+ case VORBIS_PLAYER:
+ LOGV(" create VorbisPlayer");
+ p = new VorbisPlayer();
+ break;
+ }
+ if (p != NULL) {
+ if (p->initCheck() == NO_ERROR) {
+ p->setNotifyCallback(cookie, notifyFunc);
+ } else {
+ p.clear();
+ }
+ }
+ if (p == NULL) {
+ LOGE("Failed to create player object");
+ }
+ return p;
+}
+
+sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
+{
+ // determine if we have the right player type
+ sp<MediaPlayerBase> p = mPlayer;
+ if ((p != NULL) && (p->playerType() != playerType)) {
+ LOGV("delete player");
+ p.clear();
+ }
+ if (p == NULL) {
+ p = android::createPlayer(playerType, this, notify);
+ }
+ return p;
+}
+
+status_t MediaPlayerService::Client::setDataSource(const char *url)
+{
+ LOGV("setDataSource(%s)", url);
+ if (url == NULL)
+ return UNKNOWN_ERROR;
+
+ if (strncmp(url, "content://", 10) == 0) {
+ // get a filedescriptor for the content Uri and
+ // pass it to the setDataSource(fd) method
+
+ String16 url16(url);
+ int fd = android::openContentProviderFile(url16);
+ if (fd < 0)
+ {
+ LOGE("Couldn't open fd for %s", url);
+ return UNKNOWN_ERROR;
+ }
+ setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
+ close(fd);
+ return mStatus;
+ } else {
+ player_type playerType = getPlayerType(url);
+ LOGV("player type = %d", playerType);
+
+ // create the right type of player
+ sp<MediaPlayerBase> p = createPlayer(playerType);
+ if (p == NULL) return NO_INIT;
+
+ if (!p->hardwareOutput()) {
+ mAudioOutput = new AudioOutput();
+ static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+ }
+
+ // now set data source
+ LOGV(" setDataSource");
+ mStatus = p->setDataSource(url);
+ if (mStatus == NO_ERROR) mPlayer = p;
+ return mStatus;
+ }
+}
+
+status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ struct stat sb;
+ int ret = fstat(fd, &sb);
+ if (ret != 0) {
+ LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+
+ LOGV("st_dev = %llu", sb.st_dev);
+ LOGV("st_mode = %u", sb.st_mode);
+ LOGV("st_uid = %lu", sb.st_uid);
+ LOGV("st_gid = %lu", sb.st_gid);
+ LOGV("st_size = %llu", sb.st_size);
+
+ if (offset >= sb.st_size) {
+ LOGE("offset error");
+ ::close(fd);
+ return UNKNOWN_ERROR;
+ }
+ if (offset + length > sb.st_size) {
+ length = sb.st_size - offset;
+ LOGV("calculated length = %lld", length);
+ }
+
+ player_type playerType = getPlayerType(fd, offset, length);
+ LOGV("player type = %d", playerType);
+
+ // create the right type of player
+ sp<MediaPlayerBase> p = createPlayer(playerType);
+ if (p == NULL) return NO_INIT;
+
+ if (!p->hardwareOutput()) {
+ mAudioOutput = new AudioOutput();
+ static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+ }
+
+ // now set data source
+ mStatus = p->setDataSource(fd, offset, length);
+ if (mStatus == NO_ERROR) mPlayer = p;
+ return mStatus;
+}
+
+status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface)
+{
+ LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->setVideoSurface(surface);
+}
+
+status_t MediaPlayerService::Client::prepareAsync()
+{
+ LOGV("[%d] prepareAsync", mConnId);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ status_t ret = p->prepareAsync();
+#if CALLBACK_ANTAGONIZER
+ LOGD("start Antagonizer");
+ if (ret == NO_ERROR) mAntagonizer->start();
+#endif
+ return ret;
+}
+
+status_t MediaPlayerService::Client::start()
+{
+ LOGV("[%d] start", mConnId);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ p->setLooping(mLoop);
+ return p->start();
+}
+
+status_t MediaPlayerService::Client::stop()
+{
+ LOGV("[%d] stop", mConnId);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->stop();
+}
+
+status_t MediaPlayerService::Client::pause()
+{
+ LOGV("[%d] pause", mConnId);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->pause();
+}
+
+status_t MediaPlayerService::Client::isPlaying(bool* state)
+{
+ *state = false;
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ *state = p->isPlaying();
+ LOGV("[%d] isPlaying: %d", mConnId, *state);
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
+{
+ LOGV("getCurrentPosition");
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ status_t ret = p->getCurrentPosition(msec);
+ if (ret == NO_ERROR) {
+ LOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
+ } else {
+ LOGE("getCurrentPosition returned %d", ret);
+ }
+ return ret;
+}
+
+status_t MediaPlayerService::Client::getDuration(int *msec)
+{
+ LOGV("getDuration");
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ status_t ret = p->getDuration(msec);
+ if (ret == NO_ERROR) {
+ LOGV("[%d] getDuration = %d", mConnId, *msec);
+ } else {
+ LOGE("getDuration returned %d", ret);
+ }
+ return ret;
+}
+
+status_t MediaPlayerService::Client::seekTo(int msec)
+{
+ LOGV("[%d] seekTo(%d)", mConnId, msec);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->seekTo(msec);
+}
+
+status_t MediaPlayerService::Client::reset()
+{
+ LOGV("[%d] reset", mConnId);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->reset();
+}
+
+status_t MediaPlayerService::Client::setAudioStreamType(int type)
+{
+ LOGV("[%d] setAudioStreamType(%d)", mConnId, type);
+ // TODO: for hardware output, call player instead
+ Mutex::Autolock l(mLock);
+ if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::Client::setLooping(int loop)
+{
+ LOGV("[%d] setLooping(%d)", mConnId, loop);
+ mLoop = loop;
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p != 0) return p->setLooping(loop);
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
+{
+ LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
+ // TODO: for hardware output, call player instead
+ Mutex::Autolock l(mLock);
+ if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
+ return NO_ERROR;
+}
+
+void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
+{
+ Client* client = static_cast<Client*>(cookie);
+ LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
+ client->mClient->notify(msg, ext1, ext2);
+}
+
+#if CALLBACK_ANTAGONIZER
+const int Antagonizer::interval = 10000; // 10 msecs
+
+Antagonizer::Antagonizer(notify_callback_f cb, void* client) :
+ mExit(false), mActive(false), mClient(client), mCb(cb)
+{
+ createThread(callbackThread, this);
+}
+
+void Antagonizer::kill()
+{
+ Mutex::Autolock _l(mLock);
+ mActive = false;
+ mExit = true;
+ mCondition.wait(mLock);
+}
+
+int Antagonizer::callbackThread(void* user)
+{
+ LOGD("Antagonizer started");
+ Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
+ while (!p->mExit) {
+ if (p->mActive) {
+ LOGV("send event");
+ p->mCb(p->mClient, 0, 0, 0);
+ }
+ usleep(interval);
+ }
+ Mutex::Autolock _l(p->mLock);
+ p->mCondition.signal();
+ LOGD("Antagonizer stopped");
+ return 0;
+}
+#endif
+
+static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
+
+sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+ LOGV("decode(%s)", url);
+ sp<MemoryBase> mem;
+ sp<MediaPlayerBase> player;
+
+ // Protect our precious, precious DRMd ringtones by only allowing
+ // decoding of http, but not filesystem paths or content Uris.
+ // If the application wants to decode those, it should open a
+ // filedescriptor for them and use that.
+ if (url != NULL && strncmp(url, "http://", 7) != 0) {
+ LOGD("Can't decode %s by path, use filedescriptor instead", url);
+ return mem;
+ }
+
+ player_type playerType = getPlayerType(url);
+ LOGV("player type = %d", playerType);
+
+ // create the right type of player
+ sp<AudioCache> cache = new AudioCache(url);
+ player = android::createPlayer(playerType, cache.get(), cache->notify);
+ if (player == NULL) goto Exit;
+ if (player->hardwareOutput()) goto Exit;
+
+ static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
+
+ // set data source
+ if (player->setDataSource(url) != NO_ERROR) goto Exit;
+
+ LOGV("prepare");
+ player->prepareAsync();
+
+ LOGV("wait for prepare");
+ if (cache->wait() != NO_ERROR) goto Exit;
+
+ LOGV("start");
+ player->start();
+
+ LOGV("wait for playback complete");
+ if (cache->wait() != NO_ERROR) goto Exit;
+
+ mem = new MemoryBase(cache->getHeap(), 0, cache->size());
+ *pSampleRate = cache->sampleRate();
+ *pNumChannels = cache->channelCount();
+ *pFormat = cache->format();
+ LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
+
+Exit:
+ if (player != 0) player->reset();
+ return mem;
+}
+
+sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+ LOGV("decode(%d, %lld, %lld)", fd, offset, length);
+ sp<MemoryBase> mem;
+ sp<MediaPlayerBase> player;
+
+ player_type playerType = getPlayerType(fd, offset, length);
+ LOGV("player type = %d", playerType);
+
+ // create the right type of player
+ sp<AudioCache> cache = new AudioCache("decode_fd");
+ player = android::createPlayer(playerType, cache.get(), cache->notify);
+ if (player == NULL) goto Exit;
+ if (player->hardwareOutput()) goto Exit;
+
+ static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
+
+ // set data source
+ if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit;
+
+ LOGV("prepare");
+ player->prepareAsync();
+
+ LOGV("wait for prepare");
+ if (cache->wait() != NO_ERROR) goto Exit;
+
+ LOGV("start");
+ player->start();
+
+ LOGV("wait for playback complete");
+ if (cache->wait() != NO_ERROR) goto Exit;
+
+ mem = new MemoryBase(cache->getHeap(), 0, cache->size());
+ *pSampleRate = cache->sampleRate();
+ *pNumChannels = cache->channelCount();
+ *pFormat = cache->format();
+ LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
+
+Exit:
+ if (player != 0) player->reset();
+ ::close(fd);
+ return mem;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioSink"
+MediaPlayerService::AudioOutput::AudioOutput()
+{
+ mTrack = 0;
+ mStreamType = AudioSystem::MUSIC;
+ mLeftVolume = 1.0;
+ mRightVolume = 1.0;
+ mLatency = 0;
+ mMsecsPerFrame = 0;
+ setMinBufferCount();
+}
+
+MediaPlayerService::AudioOutput::~AudioOutput()
+{
+ close();
+}
+
+void MediaPlayerService::AudioOutput::setMinBufferCount()
+{
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ mIsOnEmulator = true;
+ mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
+ }
+}
+
+bool MediaPlayerService::AudioOutput::isOnEmulator()
+{
+ setMinBufferCount();
+ return mIsOnEmulator;
+}
+
+int MediaPlayerService::AudioOutput::getMinBufferCount()
+{
+ setMinBufferCount();
+ return mMinBufferCount;
+}
+
+ssize_t MediaPlayerService::AudioOutput::bufferSize() const
+{
+ if (mTrack == 0) return NO_INIT;
+ return mTrack->frameCount() * frameSize();
+}
+
+ssize_t MediaPlayerService::AudioOutput::frameCount() const
+{
+ if (mTrack == 0) return NO_INIT;
+ return mTrack->frameCount();
+}
+
+ssize_t MediaPlayerService::AudioOutput::channelCount() const
+{
+ if (mTrack == 0) return NO_INIT;
+ return mTrack->channelCount();
+}
+
+ssize_t MediaPlayerService::AudioOutput::frameSize() const
+{
+ if (mTrack == 0) return NO_INIT;
+ return mTrack->frameSize();
+}
+
+uint32_t MediaPlayerService::AudioOutput::latency () const
+{
+ return mLatency;
+}
+
+float MediaPlayerService::AudioOutput::msecsPerFrame() const
+{
+ return mMsecsPerFrame;
+}
+
+status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+{
+ // Check argument "bufferCount" against the mininum buffer count
+ if (bufferCount < mMinBufferCount) {
+ LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
+ bufferCount = mMinBufferCount;
+
+ }
+ LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
+ if (mTrack) close();
+ int afSampleRate;
+ int afFrameCount;
+ int frameCount;
+
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+
+ 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;
+ return NO_INIT;
+ }
+
+ LOGV("setVolume");
+ t->setVolume(mLeftVolume, mRightVolume);
+ mMsecsPerFrame = 1.e3 / (float) sampleRate;
+ mLatency = t->latency() + kAudioVideoDelayMs;
+ mTrack = t;
+ return NO_ERROR;
+}
+
+void MediaPlayerService::AudioOutput::start()
+{
+ LOGV("start");
+ if (mTrack) {
+ mTrack->setVolume(mLeftVolume, mRightVolume);
+ mTrack->start();
+ }
+}
+
+ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
+{
+ //LOGV("write(%p, %u)", buffer, size);
+ if (mTrack) return mTrack->write(buffer, size);
+ return NO_INIT;
+}
+
+void MediaPlayerService::AudioOutput::stop()
+{
+ LOGV("stop");
+ if (mTrack) mTrack->stop();
+}
+
+void MediaPlayerService::AudioOutput::flush()
+{
+ LOGV("flush");
+ if (mTrack) mTrack->flush();
+}
+
+void MediaPlayerService::AudioOutput::pause()
+{
+ LOGV("pause");
+ if (mTrack) mTrack->pause();
+}
+
+void MediaPlayerService::AudioOutput::close()
+{
+ LOGV("close");
+ delete mTrack;
+ mTrack = 0;
+}
+
+void MediaPlayerService::AudioOutput::setVolume(float left, float right)
+{
+ LOGV("setVolume(%f, %f)", left, right);
+ mLeftVolume = left;
+ mRightVolume = right;
+ if (mTrack) {
+ mTrack->setVolume(left, right);
+ }
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioCache"
+MediaPlayerService::AudioCache::AudioCache(const char* name) :
+ mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
+ mError(NO_ERROR), mCommandComplete(false)
+{
+ // create ashmem heap
+ mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name);
+}
+
+uint32_t MediaPlayerService::AudioCache::latency () const
+{
+ return 0;
+}
+
+float MediaPlayerService::AudioCache::msecsPerFrame() const
+{
+ return mMsecsPerFrame;
+}
+
+status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+{
+ LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
+ if (mHeap->getHeapID() < 0) return NO_INIT;
+ mSampleRate = sampleRate;
+ mChannelCount = (uint16_t)channelCount;
+ mFormat = (uint16_t)format;
+ mMsecsPerFrame = 1.e3 / (float) sampleRate;
+ return NO_ERROR;
+}
+
+ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size)
+{
+ LOGV("write(%p, %u)", buffer, size);
+ if ((buffer == 0) || (size == 0)) return size;
+
+ uint8_t* p = static_cast<uint8_t*>(mHeap->getBase());
+ if (p == NULL) return NO_INIT;
+ p += mSize;
+ LOGV("memcpy(%p, %p, %u)", p, buffer, size);
+ if (mSize + size > mHeap->getSize()) {
+ LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
+ size = mHeap->getSize() - mSize;
+ }
+ memcpy(p, buffer, size);
+ mSize += size;
+ return size;
+}
+
+// call with lock held
+status_t MediaPlayerService::AudioCache::wait()
+{
+ Mutex::Autolock lock(mLock);
+ if (!mCommandComplete) {
+ mSignal.wait(mLock);
+ }
+ mCommandComplete = false;
+
+ if (mError == NO_ERROR) {
+ LOGV("wait - success");
+ } else {
+ LOGV("wait - error");
+ }
+ return mError;
+}
+
+void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
+{
+ LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
+ AudioCache* p = static_cast<AudioCache*>(cookie);
+
+ // ignore buffering messages
+ if (msg == MEDIA_BUFFERING_UPDATE) return;
+
+ // set error condition
+ if (msg == MEDIA_ERROR) {
+ LOGE("Error %d, %d occurred", ext1, ext2);
+ p->mError = ext1;
+ }
+
+ // wake up thread
+ LOGV("wakeup thread");
+ p->mCommandComplete = true;
+ p->mSignal.signal();
+}
+
+}; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
new file mode 100644
index 0000000..f138886
--- /dev/null
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -0,0 +1,238 @@
+/*
+**
+** Copyright 2008, 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_MEDIAPLAYERSERVICE_H
+#define ANDROID_MEDIAPLAYERSERVICE_H
+
+#include <utils.h>
+#include <utils/KeyedVector.h>
+#include <ui/SurfaceComposerClient.h>
+
+#include <media/IMediaPlayerService.h>
+#include <media/MediaPlayerInterface.h>
+
+namespace android {
+
+class IMediaRecorder;
+class IMediaMetadataRetriever;
+
+#define CALLBACK_ANTAGONIZER 0
+#if CALLBACK_ANTAGONIZER
+class Antagonizer {
+public:
+ Antagonizer(notify_callback_f cb, void* client);
+ void start() { mActive = true; }
+ void stop() { mActive = false; }
+ void kill();
+private:
+ static const int interval;
+ Antagonizer();
+ static int callbackThread(void* cookie);
+ Mutex mLock;
+ Condition mCondition;
+ bool mExit;
+ bool mActive;
+ void* mClient;
+ notify_callback_f mCb;
+};
+#endif
+
+class MediaPlayerService : public BnMediaPlayerService
+{
+ class Client;
+
+ class AudioOutput : public MediaPlayerBase::AudioSink
+ {
+ public:
+ AudioOutput();
+ virtual ~AudioOutput();
+
+ virtual bool ready() const { return mTrack != NULL; }
+ virtual bool realtime() const { return true; }
+ virtual ssize_t bufferSize() const;
+ virtual ssize_t frameCount() const;
+ virtual ssize_t channelCount() const;
+ virtual ssize_t frameSize() const;
+ virtual uint32_t latency() const;
+ virtual float msecsPerFrame() const;
+ virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4);
+ virtual void start();
+ virtual ssize_t write(const void* buffer, size_t size);
+ virtual void stop();
+ virtual void flush();
+ virtual void pause();
+ virtual void close();
+ void setAudioStreamType(int streamType) { mStreamType = streamType; }
+ void setVolume(float left, float right);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+ static bool isOnEmulator();
+ static int getMinBufferCount();
+ private:
+ static void setMinBufferCount();
+
+ AudioTrack* mTrack;
+ int mStreamType;
+ float mLeftVolume;
+ float mRightVolume;
+ float mMsecsPerFrame;
+ uint32_t mLatency;
+
+ // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
+ static const uint32_t kAudioVideoDelayMs;
+ static bool mIsOnEmulator;
+ static int mMinBufferCount; // 12 for emulator; otherwise 4
+
+ };
+
+ class AudioCache : public MediaPlayerBase::AudioSink
+ {
+ public:
+ AudioCache(const char* name);
+ virtual ~AudioCache() {}
+
+ virtual bool ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); }
+ virtual bool realtime() const { return false; }
+ virtual ssize_t bufferSize() const { return frameSize() * mFrameCount; }
+ virtual ssize_t frameCount() const { return mFrameCount; }
+ virtual ssize_t channelCount() const { return (ssize_t)mChannelCount; }
+ virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
+ virtual uint32_t latency() const;
+ virtual float msecsPerFrame() const;
+ virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1);
+ virtual void start() {}
+ virtual ssize_t write(const void* buffer, size_t size);
+ virtual void stop() {}
+ virtual void flush() {}
+ virtual void pause() {}
+ virtual void close() {}
+ void setAudioStreamType(int streamType) {}
+ void setVolume(float left, float right) {}
+ uint32_t sampleRate() const { return mSampleRate; }
+ uint32_t format() const { return (uint32_t)mFormat; }
+ size_t size() const { return mSize; }
+ status_t wait();
+
+ sp<IMemoryHeap> getHeap() const { return mHeap; }
+
+ static void notify(void* cookie, int msg, int ext1, int ext2);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+ private:
+ AudioCache();
+
+ Mutex mLock;
+ Condition mSignal;
+ sp<MemoryHeapBase> mHeap;
+ float mMsecsPerFrame;
+ uint16_t mChannelCount;
+ uint16_t mFormat;
+ ssize_t mFrameCount;
+ uint32_t mSampleRate;
+ uint32_t mSize;
+ int mError;
+ bool mCommandComplete;
+ };
+
+public:
+ static void instantiate();
+
+ // IMediaPlayerService interface
+ virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid);
+ virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
+
+ // House keeping for media player clients
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
+ virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+ virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ void removeClient(wp<Client> client);
+
+private:
+
+ class Client : public BnMediaPlayer {
+
+ // IMediaPlayer interface
+ virtual void disconnect();
+ virtual status_t setVideoSurface(const sp<ISurface>& surface);
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual status_t isPlaying(bool* state);
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int* msec);
+ virtual status_t getDuration(int* msec);
+ virtual status_t reset();
+ virtual status_t setAudioStreamType(int type);
+ virtual status_t setLooping(int loop);
+ virtual status_t setVolume(float leftVolume, float rightVolume);
+
+ sp<MediaPlayerBase> createPlayer(player_type playerType);
+ status_t setDataSource(const char *url);
+ status_t setDataSource(int fd, int64_t offset, int64_t length);
+ static void notify(void* cookie, int msg, int ext1, int ext2);
+
+ pid_t pid() const { return mPid; }
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+ private:
+ friend class MediaPlayerService;
+ Client( const sp<MediaPlayerService>& service,
+ pid_t pid,
+ int32_t connId,
+ const sp<IMediaPlayerClient>& client);
+ Client();
+ virtual ~Client();
+
+ void deletePlayer();
+
+ sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
+
+ mutable Mutex mLock;
+ sp<MediaPlayerBase> mPlayer;
+ sp<MediaPlayerService> mService;
+ sp<IMediaPlayerClient> mClient;
+ sp<AudioOutput> mAudioOutput;
+ pid_t mPid;
+ status_t mStatus;
+ bool mLoop;
+ int32_t mConnId;
+#if CALLBACK_ANTAGONIZER
+ Antagonizer* mAntagonizer;
+#endif
+ };
+
+// ----------------------------------------------------------------------------
+
+ MediaPlayerService();
+ virtual ~MediaPlayerService();
+
+ mutable Mutex mLock;
+ SortedVector< wp<Client> > mClients;
+ int32_t mNextConnId;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYERSERVICE_H
+
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
new file mode 100644
index 0000000..4b45acb
--- /dev/null
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -0,0 +1,273 @@
+/*
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_NDEBUG 0
+#define LOG_TAG "MediaRecorderService"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <cutils/atomic.h>
+#include <android_runtime/ActivityManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/MemoryBase.h>
+#include <media/PVMediaRecorder.h>
+
+#include "MediaRecorderClient.h"
+
+namespace android {
+
+status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
+{
+ LOGV("setCamera");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setCamera(camera);
+}
+
+status_t MediaRecorderClient::setPreviewSurface(const sp<ISurface>& surface)
+{
+ LOGV("setPreviewSurface");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setPreviewSurface(surface);
+}
+
+status_t MediaRecorderClient::setVideoSource(int vs)
+{
+ LOGV("setVideoSource(%d)", vs);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ }
+ return mRecorder->setVideoSource((video_source)vs);
+}
+
+status_t MediaRecorderClient::setAudioSource(int as)
+{
+ LOGV("setAudioSource(%d)", as);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ }
+ return mRecorder->setAudioSource((audio_source)as);
+}
+
+status_t MediaRecorderClient::setOutputFormat(int of)
+{
+ LOGV("setOutputFormat(%d)", of);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setOutputFormat((output_format)of);
+}
+
+status_t MediaRecorderClient::setVideoEncoder(int ve)
+{
+ LOGV("setVideoEncoder(%d)", ve);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setVideoEncoder((video_encoder)ve);
+}
+
+status_t MediaRecorderClient::setAudioEncoder(int ae)
+{
+ LOGV("setAudioEncoder(%d)", ae);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setAudioEncoder((audio_encoder)ae);
+}
+
+status_t MediaRecorderClient::setOutputFile(const char* path)
+{
+ LOGV("setOutputFile(%s)", path);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ 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);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setVideoSize(width, height);
+}
+
+status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
+{
+ LOGV("setVideoFrameRate(%d)", frames_per_second);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setVideoFrameRate(frames_per_second);
+}
+
+status_t MediaRecorderClient::prepare()
+{
+ LOGV("prepare");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->prepare();
+}
+
+
+status_t MediaRecorderClient::getMaxAmplitude(int* max)
+{
+ LOGV("getMaxAmplitude");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->getMaxAmplitude(max);
+}
+
+status_t MediaRecorderClient::start()
+{
+ LOGV("start");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->start();
+
+}
+
+status_t MediaRecorderClient::stop()
+{
+ LOGV("stop");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->stop();
+}
+
+status_t MediaRecorderClient::init()
+{
+ LOGV("init");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->init();
+}
+
+status_t MediaRecorderClient::close()
+{
+ LOGV("close");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->close();
+}
+
+
+status_t MediaRecorderClient::reset()
+{
+ LOGV("reset");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->reset();
+}
+
+status_t MediaRecorderClient::release()
+{
+ LOGV("release");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder != NULL) {
+ delete mRecorder;
+ mRecorder = NULL;
+ }
+ return NO_ERROR;
+}
+
+MediaRecorderClient::MediaRecorderClient(pid_t pid)
+{
+ LOGV("Client constructor");
+ mPid = pid;
+ mRecorder = new PVMediaRecorder();
+}
+
+MediaRecorderClient::~MediaRecorderClient()
+{
+ LOGV("Client destructor");
+ 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
new file mode 100644
index 0000000..93fd802
--- /dev/null
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -0,0 +1,66 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_MEDIARECORDERCLIENT_H
+#define ANDROID_MEDIARECORDERCLIENT_H
+
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class PVMediaRecorder;
+class ISurface;
+
+class MediaRecorderClient : public BnMediaRecorder
+{
+public:
+ virtual status_t setCamera(const sp<ICamera>& camera);
+ virtual status_t setPreviewSurface(const sp<ISurface>& surface);
+ virtual status_t setVideoSource(int vs);
+ virtual status_t setAudioSource(int as);
+ virtual status_t setOutputFormat(int of);
+ 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 setListener(const sp<IMediaPlayerClient>& listener);
+ virtual status_t prepare();
+ virtual status_t getMaxAmplitude(int* max);
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t reset();
+ virtual status_t init();
+ virtual status_t close();
+ virtual status_t release();
+
+private:
+ friend class MediaPlayerService; // for accessing private constructor
+
+ MediaRecorderClient(pid_t pid);
+ virtual ~MediaRecorderClient();
+
+ pid_t mPid;
+ Mutex mLock;
+ PVMediaRecorder *mRecorder;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIARECORDERCLIENT_H
+
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
new file mode 100644
index 0000000..a320bd5
--- /dev/null
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -0,0 +1,250 @@
+/*
+**
+** Copyright (C) 2008 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_NDEBUG 0
+#define LOG_TAG "MetadataRetrieverClient"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <cutils/atomic.h>
+#include <utils/MemoryDealer.h>
+#include <android_runtime/ActivityManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/PVMetadataRetriever.h>
+#include <private/media/VideoFrame.h>
+
+#include "MetadataRetrieverClient.h"
+
+
+namespace android {
+
+MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
+{
+ LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
+ mPid = pid;
+ mThumbnailDealer = NULL;
+ mAlbumArtDealer = NULL;
+ mThumbnail = NULL;
+ mAlbumArt = NULL;
+
+ mRetriever = new PVMetadataRetriever();
+ if (mRetriever == NULL) {
+ LOGE("failed to initialize the retriever");
+ }
+}
+
+MetadataRetrieverClient::~MetadataRetrieverClient()
+{
+ LOGV("MetadataRetrieverClient destructor");
+ disconnect();
+}
+
+status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append(" MetadataRetrieverClient\n");
+ snprintf(buffer, 255, " pid(%d)\n", mPid);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ write(fd, "\n", 1);
+ return NO_ERROR;
+}
+
+void MetadataRetrieverClient::disconnect()
+{
+ LOGV("disconnect from pid %d", mPid);
+ Mutex::Autolock lock(mLock);
+ mRetriever.clear();
+ mThumbnailDealer.clear();
+ mAlbumArtDealer.clear();
+ mThumbnail.clear();
+ mAlbumArt.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+status_t MetadataRetrieverClient::setDataSource(const char *url)
+{
+ LOGV("setDataSource(%s)", url);
+ Mutex::Autolock lock(mLock);
+ if (url == NULL) {
+ return UNKNOWN_ERROR;
+ }
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NO_INIT;
+ }
+ return mRetriever->setDataSource(url);
+}
+
+status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ Mutex::Autolock lock(mLock);
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ ::close(fd);
+ return NO_INIT;
+ }
+
+ struct stat sb;
+ int ret = fstat(fd, &sb);
+ if (ret != 0) {
+ LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+ LOGV("st_dev = %llu", sb.st_dev);
+ LOGV("st_mode = %u", sb.st_mode);
+ LOGV("st_uid = %lu", sb.st_uid);
+ LOGV("st_gid = %lu", sb.st_gid);
+ LOGV("st_size = %llu", sb.st_size);
+
+ if (offset >= sb.st_size) {
+ LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
+ ::close(fd);
+ return UNKNOWN_ERROR;
+ }
+ if (offset + length > sb.st_size) {
+ length = sb.st_size - offset;
+ LOGE("calculated length = %lld", length);
+ }
+ status_t status = mRetriever->setDataSource(fd, offset, length);
+ ::close(fd);
+ return status;
+}
+
+status_t MetadataRetrieverClient::setMode(int mode)
+{
+ LOGV("setMode");
+ Mutex::Autolock lock(mLock);
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NO_INIT;
+ }
+ return mRetriever->setMode(mode);
+}
+
+status_t MetadataRetrieverClient::getMode(int* mode) const
+{
+ LOGV("getMode");
+ Mutex::Autolock lock(mLock);
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NO_INIT;
+ }
+ return mRetriever->getMode(mode);
+}
+
+sp<IMemory> MetadataRetrieverClient::captureFrame()
+{
+ LOGV("captureFrame");
+ Mutex::Autolock lock(mLock);
+ mThumbnail.clear();
+ mThumbnailDealer.clear();
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ VideoFrame *frame = mRetriever->captureFrame();
+ if (frame == NULL) {
+ LOGE("failed to capture a video frame");
+ return NULL;
+ }
+ size_t size = sizeof(VideoFrame) + frame->mSize;
+ mThumbnailDealer = new MemoryDealer(size);
+ if (mThumbnailDealer == NULL) {
+ LOGE("failed to create MemoryDealer");
+ delete frame;
+ return NULL;
+ }
+ mThumbnail = mThumbnailDealer->allocate(size);
+ if (mThumbnail == NULL) {
+ LOGE("not enough memory for VideoFrame size=%u", size);
+ mThumbnailDealer.clear();
+ delete frame;
+ return NULL;
+ }
+ VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
+ frameCopy->mWidth = frame->mWidth;
+ frameCopy->mHeight = frame->mHeight;
+ frameCopy->mDisplayWidth = frame->mDisplayWidth;
+ frameCopy->mDisplayHeight = frame->mDisplayHeight;
+ frameCopy->mSize = frame->mSize;
+ frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
+ memcpy(frameCopy->mData, frame->mData, frame->mSize);
+ delete frame; // Fix memory leakage
+ return mThumbnail;
+}
+
+sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
+{
+ LOGV("extractAlbumArt");
+ Mutex::Autolock lock(mLock);
+ mAlbumArt.clear();
+ mAlbumArtDealer.clear();
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
+ if (albumArt == NULL) {
+ LOGE("failed to extract an album art");
+ return NULL;
+ }
+ size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
+ mAlbumArtDealer = new MemoryDealer(size);
+ if (mAlbumArtDealer == NULL) {
+ LOGE("failed to create MemoryDealer object");
+ delete albumArt;
+ return NULL;
+ }
+ mAlbumArt = mAlbumArtDealer->allocate(size);
+ if (mAlbumArt == NULL) {
+ LOGE("not enough memory for MediaAlbumArt size=%u", size);
+ mAlbumArtDealer.clear();
+ delete albumArt;
+ return NULL;
+ }
+ MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
+ albumArtCopy->mSize = albumArt->mSize;
+ albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
+ memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
+ delete albumArt; // Fix memory leakage
+ return mAlbumArt;
+}
+
+const char* MetadataRetrieverClient::extractMetadata(int keyCode)
+{
+ LOGV("extractMetadata");
+ Mutex::Autolock lock(mLock);
+ if (mRetriever == NULL) {
+ LOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->extractMetadata(keyCode);
+}
+
+}; // namespace android
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
new file mode 100644
index 0000000..ce29c98
--- /dev/null
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -0,0 +1,71 @@
+/*
+**
+** Copyright (C) 2008 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_MEDIAMETADATARETRIEVERSERVICE_H
+#define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
+
+#include <utils.h>
+#include <utils/KeyedVector.h>
+#include <utils/IMemory.h>
+
+#include <media/MediaMetadataRetrieverInterface.h>
+
+
+namespace android {
+
+class IMediaPlayerService;
+class MemoryDealer;
+
+class MetadataRetrieverClient : public BnMediaMetadataRetriever
+{
+public:
+ MetadataRetrieverClient(const sp<IMediaPlayerService>& service, pid_t pid, int32_t connId);
+
+ // Implements IMediaMetadataRetriever interface
+ // These methods are called in IMediaMetadataRetriever.cpp?
+ virtual void disconnect();
+ virtual status_t setDataSource(const char *url);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setMode(int mode);
+ virtual status_t getMode(int* mode) const;
+ virtual sp<IMemory> captureFrame();
+ virtual sp<IMemory> extractAlbumArt();
+ virtual const char* extractMetadata(int keyCode);
+
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+ friend class MediaPlayerService;
+
+ explicit MetadataRetrieverClient(pid_t pid);
+ virtual ~MetadataRetrieverClient();
+
+ mutable Mutex mLock;
+ sp<MediaMetadataRetrieverBase> mRetriever;
+ pid_t mPid;
+
+ // Keep the shared memory copy of album art and capture frame (for thumbnail)
+ sp<MemoryDealer> mAlbumArtDealer;
+ sp<MemoryDealer> mThumbnailDealer;
+ sp<IMemory> mAlbumArt;
+ sp<IMemory> mThumbnail;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
+
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
new file mode 100644
index 0000000..d03caa5
--- /dev/null
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -0,0 +1,558 @@
+/* MidiFile.cpp
+**
+** Copyright 2007, 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_NDEBUG 0
+#define LOG_TAG "MidiFile"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <utils/threads.h>
+#include <libsonivox/eas_reverb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "MidiFile.h"
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// The midi engine buffers are a bit small (128 frames), so we batch them up
+static const int NUM_BUFFERS = 4;
+
+// TODO: Determine appropriate return codes
+static status_t ERROR_NOT_OPEN = -1;
+static status_t ERROR_OPEN_FAILED = -2;
+static status_t ERROR_EAS_FAILURE = -3;
+static status_t ERROR_ALLOCATE_FAILED = -4;
+
+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(AudioSystem::MUSIC), mLoop(false), mExit(false),
+ mPaused(false), mRender(false), mTid(-1)
+{
+ LOGV("constructor");
+
+ mFileLocator.path = NULL;
+ mFileLocator.fd = -1;
+ mFileLocator.offset = 0;
+ mFileLocator.length = 0;
+
+ // get the library configuration and do sanity check
+ if (pLibConfig == NULL)
+ pLibConfig = EAS_Config();
+ if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
+ LOGE("EAS library/header mismatch");
+ goto Failed;
+ }
+
+ // initialize EAS library
+ if (EAS_Init(&mEasData) != EAS_SUCCESS) {
+ LOGE("EAS_Init failed");
+ goto Failed;
+ }
+
+ // select reverb preset and enable
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
+
+ // create playback thread
+ {
+ Mutex::Autolock l(mMutex);
+ createThreadEtc(renderThread, this, "midithread");
+ mCondition.wait(mMutex);
+ LOGV("thread started");
+ }
+
+ // indicate success
+ if (mTid > 0) {
+ LOGV(" render thread(%d) started", mTid);
+ mState = EAS_STATE_READY;
+ }
+
+Failed:
+ return;
+}
+
+status_t MidiFile::initCheck()
+{
+ if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE;
+ return NO_ERROR;
+}
+
+MidiFile::~MidiFile() {
+ LOGV("MidiFile destructor");
+ release();
+}
+
+status_t MidiFile::setDataSource(const char* path)
+{
+ LOGV("MidiFile::setDataSource url=%s", path);
+ Mutex::Autolock lock(mMutex);
+
+ // file still open?
+ if (mEasHandle) {
+ reset_nosync();
+ }
+
+ // open file and set paused state
+ mFileLocator.path = strdup(path);
+ mFileLocator.fd = -1;
+ mFileLocator.offset = 0;
+ mFileLocator.length = 0;
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
+ if (result == EAS_SUCCESS) {
+ updateState();
+ }
+
+ if (result != EAS_SUCCESS) {
+ LOGE("EAS_OpenFile failed: [%d]", (int)result);
+ mState = EAS_STATE_ERROR;
+ return ERROR_OPEN_FAILED;
+ }
+
+ mState = EAS_STATE_OPEN;
+ mPlayTime = 0;
+ return NO_ERROR;
+}
+
+status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("MidiFile::setDataSource fd=%d", fd);
+ Mutex::Autolock lock(mMutex);
+
+ // file still open?
+ if (mEasHandle) {
+ reset_nosync();
+ }
+
+ // open file and set paused state
+ mFileLocator.fd = dup(fd);
+ mFileLocator.offset = offset;
+ mFileLocator.length = length;
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
+ updateState();
+
+ if (result != EAS_SUCCESS) {
+ LOGE("EAS_OpenFile failed: [%d]", (int)result);
+ mState = EAS_STATE_ERROR;
+ return ERROR_OPEN_FAILED;
+ }
+
+ mState = EAS_STATE_OPEN;
+ mPlayTime = 0;
+ return NO_ERROR;
+}
+
+status_t MidiFile::prepare()
+{
+ LOGV("MidiFile::prepare");
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+ EAS_RESULT result;
+ if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) {
+ LOGE("EAS_Prepare failed: [%ld]", result);
+ return ERROR_EAS_FAILURE;
+ }
+ updateState();
+ return NO_ERROR;
+}
+
+status_t MidiFile::prepareAsync()
+{
+ LOGV("MidiFile::prepareAsync");
+ status_t ret = prepare();
+
+ // don't hold lock during callback
+ if (ret == NO_ERROR) {
+ sendEvent(MEDIA_PREPARED);
+ } else {
+ sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret);
+ }
+ return ret;
+}
+
+status_t MidiFile::start()
+{
+ LOGV("MidiFile::start");
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+
+ // resuming after pause?
+ if (mPaused) {
+ if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) {
+ return ERROR_EAS_FAILURE;
+ }
+ mPaused = false;
+ updateState();
+ }
+
+ mRender = true;
+
+ // wake up render thread
+ LOGV(" wakeup render thread");
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t MidiFile::stop()
+{
+ LOGV("MidiFile::stop");
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+ if (!mPaused && (mState != EAS_STATE_STOPPED)) {
+ EAS_RESULT result = EAS_Pause(mEasData, mEasHandle);
+ if (result != EAS_SUCCESS) {
+ LOGE("EAS_Pause returned error %ld", result);
+ return ERROR_EAS_FAILURE;
+ }
+ }
+ mPaused = false;
+ return NO_ERROR;
+}
+
+status_t MidiFile::seekTo(int position)
+{
+ LOGV("MidiFile::seekTo %d", position);
+ // hold lock during EAS calls
+ {
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+ EAS_RESULT result;
+ if ((result = EAS_Locate(mEasData, mEasHandle, position, false))
+ != EAS_SUCCESS)
+ {
+ LOGE("EAS_Locate returned %ld", result);
+ return ERROR_EAS_FAILURE;
+ }
+ EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
+ }
+ sendEvent(MEDIA_SEEK_COMPLETE);
+ return NO_ERROR;
+}
+
+status_t MidiFile::pause()
+{
+ LOGV("MidiFile::pause");
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+ if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR;
+ if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) {
+ return ERROR_EAS_FAILURE;
+ }
+ mPaused = true;
+ return NO_ERROR;
+}
+
+bool MidiFile::isPlaying()
+{
+ LOGV("MidiFile::isPlaying, mState=%d", int(mState));
+ if (!mEasHandle || mPaused) return false;
+ return (mState == EAS_STATE_PLAY);
+}
+
+status_t MidiFile::getCurrentPosition(int* position)
+{
+ LOGV("MidiFile::getCurrentPosition");
+ if (!mEasHandle) {
+ LOGE("getCurrentPosition(): file not open");
+ return ERROR_NOT_OPEN;
+ }
+ if (mPlayTime < 0) {
+ LOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime);
+ return ERROR_EAS_FAILURE;
+ }
+ *position = mPlayTime;
+ return NO_ERROR;
+}
+
+status_t MidiFile::getDuration(int* duration)
+{
+
+ LOGV("MidiFile::getDuration");
+ {
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) return ERROR_NOT_OPEN;
+ *duration = mDuration;
+ }
+
+ // if no duration cached, get the duration
+ // don't need a lock here because we spin up a new engine
+ if (*duration < 0) {
+ EAS_I32 temp;
+ EAS_DATA_HANDLE easData = NULL;
+ EAS_HANDLE easHandle = NULL;
+ EAS_RESULT result = EAS_Init(&easData);
+ if (result == EAS_SUCCESS) {
+ result = EAS_OpenFile(easData, &mFileLocator, &easHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_Prepare(easData, easHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_ParseMetaData(easData, easHandle, &temp);
+ }
+ if (easHandle) {
+ EAS_CloseFile(easData, easHandle);
+ }
+ if (easData) {
+ EAS_Shutdown(easData);
+ }
+
+ if (result != EAS_SUCCESS) {
+ return ERROR_EAS_FAILURE;
+ }
+
+ // cache successful result
+ mDuration = *duration = int(temp);
+ }
+
+ return NO_ERROR;
+}
+
+status_t MidiFile::release()
+{
+ LOGV("MidiFile::release");
+ Mutex::Autolock l(mMutex);
+ reset_nosync();
+
+ // wait for render thread to exit
+ mExit = true;
+ mCondition.signal();
+
+ // wait for thread to exit
+ if (mAudioBuffer) {
+ mCondition.wait(mMutex);
+ }
+
+ // release resources
+ if (mEasData) {
+ EAS_Shutdown(mEasData);
+ mEasData = NULL;
+ }
+ return NO_ERROR;
+}
+
+status_t MidiFile::reset()
+{
+ LOGV("MidiFile::reset");
+ Mutex::Autolock lock(mMutex);
+ return reset_nosync();
+}
+
+// call only with mutex held
+status_t MidiFile::reset_nosync()
+{
+ LOGV("MidiFile::reset_nosync");
+ // close file
+ if (mEasHandle) {
+ EAS_CloseFile(mEasData, mEasHandle);
+ mEasHandle = NULL;
+ }
+ if (mFileLocator.path) {
+ free((void*)mFileLocator.path);
+ mFileLocator.path = NULL;
+ }
+ if (mFileLocator.fd >= 0) {
+ close(mFileLocator.fd);
+ }
+ mFileLocator.fd = -1;
+ mFileLocator.offset = 0;
+ mFileLocator.length = 0;
+
+ mPlayTime = -1;
+ mDuration = -1;
+ mLoop = false;
+ mPaused = false;
+ mRender = false;
+ return NO_ERROR;
+}
+
+status_t MidiFile::setLooping(int loop)
+{
+ LOGV("MidiFile::setLooping");
+ Mutex::Autolock lock(mMutex);
+ if (!mEasHandle) {
+ return ERROR_NOT_OPEN;
+ }
+ loop = loop ? -1 : 0;
+ if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) {
+ return ERROR_EAS_FAILURE;
+ }
+ return NO_ERROR;
+}
+
+status_t MidiFile::createOutputTrack() {
+ if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels, AudioSystem::PCM_16_BIT, 2) != NO_ERROR) {
+ LOGE("mAudioSink open failed");
+ return ERROR_OPEN_FAILED;
+ }
+ return NO_ERROR;
+}
+
+int MidiFile::renderThread(void* p) {
+
+ return ((MidiFile*)p)->render();
+}
+
+int MidiFile::render() {
+ EAS_RESULT result = EAS_FAILURE;
+ EAS_I32 count;
+ int temp;
+ bool audioStarted = false;
+
+ LOGV("MidiFile::render");
+
+ // allocate render buffer
+ mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
+ if (!mAudioBuffer) {
+ LOGE("mAudioBuffer allocate failed");
+ goto threadExit;
+ }
+
+ // signal main thread that we started
+ {
+ Mutex::Autolock l(mMutex);
+ mTid = myTid();
+ LOGV("render thread(%d) signal", mTid);
+ mCondition.signal();
+ }
+
+ while (1) {
+ mMutex.lock();
+
+ // nothing to render, wait for client thread to wake us up
+ while (!mRender && !mExit)
+ {
+ LOGV("MidiFile::render - signal wait");
+ mCondition.wait(mMutex);
+ LOGV("MidiFile::render - signal rx'd");
+ }
+ if (mExit) {
+ mMutex.unlock();
+ break;
+ }
+
+ // render midi data into the input buffer
+ //LOGV("MidiFile::render - rendering audio");
+ int num_output = 0;
+ EAS_PCM* p = mAudioBuffer;
+ for (int i = 0; i < NUM_BUFFERS; i++) {
+ result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
+ if (result != EAS_SUCCESS) {
+ LOGE("EAS_Render returned %ld", result);
+ }
+ p += count * pLibConfig->numChannels;
+ num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
+ }
+
+ // update playback state and position
+ // LOGV("MidiFile::render - updating state");
+ EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
+ EAS_State(mEasData, mEasHandle, &mState);
+ mMutex.unlock();
+
+ // create audio output track if necessary
+ if (!mAudioSink->ready()) {
+ LOGV("MidiFile::render - create output track");
+ if (createOutputTrack() != NO_ERROR)
+ goto threadExit;
+ }
+
+ // Write data to the audio hardware
+ // LOGV("MidiFile::render - writing to audio output");
+ if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) {
+ LOGE("Error in writing:%d",temp);
+ return temp;
+ }
+
+ // start audio output if necessary
+ if (!audioStarted) {
+ //LOGV("MidiFile::render - starting audio");
+ mAudioSink->start();
+ audioStarted = true;
+ }
+
+ // still playing?
+ if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) ||
+ (mState == EAS_STATE_PAUSED))
+ {
+ switch(mState) {
+ case EAS_STATE_STOPPED:
+ {
+ LOGV("MidiFile::render - stopped");
+ sendEvent(MEDIA_PLAYBACK_COMPLETE);
+ break;
+ }
+ case EAS_STATE_ERROR:
+ {
+ LOGE("MidiFile::render - error");
+ sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN);
+ break;
+ }
+ case EAS_STATE_PAUSED:
+ LOGV("MidiFile::render - paused");
+ break;
+ default:
+ break;
+ }
+ mAudioSink->stop();
+ audioStarted = false;
+ mRender = false;
+ }
+ }
+
+threadExit:
+ mAudioSink.clear();
+ if (mAudioBuffer) {
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mMutex.lock();
+ mTid = -1;
+ mCondition.signal();
+ mMutex.unlock();
+ return result;
+}
+
+} // end namespace android
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
new file mode 100644
index 0000000..302f1cf
--- /dev/null
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright 2008, 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_MIDIFILE_H
+#define ANDROID_MIDIFILE_H
+
+#include <media/MediaPlayerInterface.h>
+#include <media/AudioTrack.h>
+#include <libsonivox/eas.h>
+
+namespace android {
+
+class MidiFile : public MediaPlayerInterface {
+public:
+ MidiFile();
+ ~MidiFile();
+
+ virtual status_t initCheck();
+ 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; }
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t seekTo(int msec);
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t getCurrentPosition(int* msec);
+ virtual status_t getDuration(int* msec);
+ virtual status_t release();
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType() { return SONIVOX_PLAYER; }
+
+private:
+ status_t createOutputTrack();
+ status_t reset_nosync();
+ static int renderThread(void*);
+ int render();
+ void updateState(){ EAS_State(mEasData, mEasHandle, &mState); }
+
+ Mutex mMutex;
+ Condition mCondition;
+ EAS_DATA_HANDLE mEasData;
+ EAS_HANDLE mEasHandle;
+ EAS_PCM* mAudioBuffer;
+ EAS_I32 mPlayTime;
+ EAS_I32 mDuration;
+ EAS_STATE mState;
+ EAS_FILE mFileLocator;
+ int mStreamType;
+ bool mLoop;
+ volatile bool mExit;
+ bool mPaused;
+ volatile bool mRender;
+ pid_t mTid;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MIDIFILE_H
+
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
new file mode 100644
index 0000000..0ad335f
--- /dev/null
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -0,0 +1,529 @@
+/*
+** Copyright 2007, 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_NDEBUG 0
+#define LOG_TAG "VorbisPlayer"
+#include "utils/Log.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#include "VorbisPlayer.h"
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// TODO: Determine appropriate return codes
+static status_t ERROR_NOT_OPEN = -1;
+static status_t ERROR_OPEN_FAILED = -2;
+static status_t ERROR_ALLOCATE_FAILED = -4;
+static status_t ERROR_NOT_SUPPORTED = -8;
+static status_t ERROR_NOT_READY = -16;
+static status_t STATE_INIT = 0;
+static status_t STATE_ERROR = 1;
+static status_t STATE_OPEN = 2;
+
+
+VorbisPlayer::VorbisPlayer() :
+ mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR),
+ mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false),
+ mExit(false), mPaused(false), mRender(false), mRenderTid(-1)
+{
+ LOGV("constructor\n");
+ memset(&mVorbisFile, 0, sizeof mVorbisFile);
+}
+
+void VorbisPlayer::onFirstRef()
+{
+ LOGV("onFirstRef");
+ // create playback thread
+ Mutex::Autolock l(mMutex);
+ createThreadEtc(renderThread, this, "vorbis decoder");
+ mCondition.wait(mMutex);
+ if (mRenderTid > 0) {
+ LOGV("render thread(%d) started", mRenderTid);
+ mState = STATE_INIT;
+ }
+}
+
+status_t VorbisPlayer::initCheck()
+{
+ if (mState != STATE_ERROR) return NO_ERROR;
+ return ERROR_NOT_READY;
+}
+
+VorbisPlayer::~VorbisPlayer() {
+ LOGV("VorbisPlayer destructor\n");
+ release();
+}
+
+status_t VorbisPlayer::setDataSource(const char* path)
+{
+ return setdatasource(path, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
+}
+
+status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ return setdatasource(NULL, fd, offset, length);
+}
+
+size_t VorbisPlayer::vp_fread(void *buf, size_t size, size_t nmemb, void *me) {
+ VorbisPlayer *self = (VorbisPlayer*) me;
+
+ long curpos = vp_ftell(me);
+ while (nmemb != 0 && (curpos + size * nmemb) > self->mLength) {
+ nmemb--;
+ }
+ return fread(buf, size, nmemb, self->mFile);
+}
+
+int VorbisPlayer::vp_fseek(void *me, ogg_int64_t off, int whence) {
+ VorbisPlayer *self = (VorbisPlayer*) me;
+ if (whence == SEEK_SET)
+ return fseek(self->mFile, off + self->mOffset, whence);
+ else if (whence == SEEK_CUR)
+ return fseek(self->mFile, off, whence);
+ else if (whence == SEEK_END)
+ return fseek(self->mFile, self->mOffset + self->mLength + off, SEEK_SET);
+ return -1;
+}
+
+int VorbisPlayer::vp_fclose(void *me) {
+ LOGV("vp_fclose");
+ VorbisPlayer *self = (VorbisPlayer*) me;
+ int ret = fclose (self->mFile);
+ self->mFile = NULL;
+ return ret;
+}
+
+long VorbisPlayer::vp_ftell(void *me) {
+ VorbisPlayer *self = (VorbisPlayer*) me;
+ return ftell(self->mFile) - self->mOffset;
+}
+
+status_t VorbisPlayer::setdatasource(const char *path, int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource url=%s, fd=%d\n", path, fd);
+
+ // file still open?
+ Mutex::Autolock l(mMutex);
+ if (mState == STATE_OPEN) {
+ reset_nosync();
+ }
+
+ // open file and set paused state
+ if (path) {
+ mFile = fopen(path, "r");
+ } else {
+ mFile = fdopen(dup(fd), "r");
+ }
+ if (mFile == NULL) {
+ return ERROR_OPEN_FAILED;
+ }
+
+ struct stat sb;
+ int ret;
+ if (path) {
+ ret = stat(path, &sb);
+ } else {
+ ret = fstat(fd, &sb);
+ }
+ if (ret != 0) {
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+ if (sb.st_size > (length + offset)) {
+ mLength = length;
+ } else {
+ mLength = sb.st_size - offset;
+ }
+
+ ov_callbacks callbacks = {
+ (size_t (*)(void *, size_t, size_t, void *)) vp_fread,
+ (int (*)(void *, ogg_int64_t, int)) vp_fseek,
+ (int (*)(void *)) vp_fclose,
+ (long (*)(void *)) vp_ftell
+ };
+
+ mOffset = offset;
+ fseek(mFile, offset, SEEK_SET);
+
+ int result = ov_open_callbacks(this, &mVorbisFile, NULL, 0, callbacks);
+ if (result < 0) {
+ LOGE("ov_open() failed: [%d]\n", (int)result);
+ mState = STATE_ERROR;
+ fclose(mFile);
+ return ERROR_OPEN_FAILED;
+ }
+
+ // look for the android loop tag (for ringtones)
+ char **ptr = ov_comment(&mVorbisFile,-1)->user_comments;
+ while(*ptr) {
+ // does the comment start with ANDROID_LOOP_TAG
+ if(strncmp(*ptr, ANDROID_LOOP_TAG, strlen(ANDROID_LOOP_TAG)) == 0) {
+ // read the value of the tag
+ char *val = *ptr + strlen(ANDROID_LOOP_TAG) + 1;
+ mAndroidLoop = (strncmp(val, "true", 4) == 0);
+ }
+ // we keep parsing even after finding one occurence of ANDROID_LOOP_TAG,
+ // as we could find another one (the tag might have been appended more than once).
+ ++ptr;
+ }
+ LOGV_IF(mAndroidLoop, "looped sound");
+
+ mState = STATE_OPEN;
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::prepare()
+{
+ LOGV("prepare\n");
+ if (mState != STATE_OPEN ) {
+ return ERROR_NOT_OPEN;
+ }
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::prepareAsync() {
+ LOGV("prepareAsync\n");
+ // can't hold the lock here because of the callback
+ // it's safe because we don't change state
+ if (mState != STATE_OPEN ) {
+ sendEvent(MEDIA_ERROR);
+ return NO_ERROR;
+ }
+ sendEvent(MEDIA_PREPARED);
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::start()
+{
+ LOGV("start\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ mPaused = false;
+ mRender = true;
+
+ // wake up render thread
+ LOGV(" wakeup render thread\n");
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::stop()
+{
+ LOGV("stop\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+ mPaused = true;
+ mRender = false;
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::seekTo(int position)
+{
+ LOGV("seekTo %d\n", position);
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ int result = ov_time_seek(&mVorbisFile, position);
+ if (result != 0) {
+ LOGE("ov_time_seek() returned %d\n", result);
+ return result;
+ }
+ sendEvent(MEDIA_SEEK_COMPLETE);
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::pause()
+{
+ LOGV("pause\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+ mPaused = true;
+ return NO_ERROR;
+}
+
+bool VorbisPlayer::isPlaying()
+{
+ LOGV("isPlaying\n");
+ if (mState == STATE_OPEN) {
+ return mRender;
+ }
+ return false;
+}
+
+status_t VorbisPlayer::getCurrentPosition(int* position)
+{
+ LOGV("getCurrentPosition\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ LOGE("getCurrentPosition(): file not open");
+ return ERROR_NOT_OPEN;
+ }
+ *position = ov_time_tell(&mVorbisFile);
+ if (*position < 0) {
+ LOGE("getCurrentPosition(): ov_time_tell returned %d", *position);
+ return *position;
+ }
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::getDuration(int* duration)
+{
+ LOGV("getDuration\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return ERROR_NOT_OPEN;
+ }
+
+ int ret = ov_time_total(&mVorbisFile, -1);
+ if (ret == OV_EINVAL) {
+ return -1;
+ }
+
+ *duration = ret;
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::release()
+{
+ LOGV("release\n");
+ Mutex::Autolock l(mMutex);
+ reset_nosync();
+
+ // TODO: timeout when thread won't exit
+ // wait for render thread to exit
+ if (mRenderTid > 0) {
+ mExit = true;
+ mCondition.signal();
+ mCondition.wait(mMutex);
+ }
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::reset()
+{
+ LOGV("reset\n");
+ Mutex::Autolock l(mMutex);
+ if (mState != STATE_OPEN) {
+ return NO_ERROR;
+ }
+ return reset_nosync();
+}
+
+// always call with lock held
+status_t VorbisPlayer::reset_nosync()
+{
+ // close file
+ ov_clear(&mVorbisFile); // this also closes the FILE
+ if (mFile != NULL) {
+ LOGV("OOPS! Vorbis didn't close the file");
+ fclose(mFile);
+ }
+ mState = STATE_ERROR;
+
+ mPlayTime = -1;
+ mDuration = -1;
+ mLoop = false;
+ mAndroidLoop = false;
+ mPaused = false;
+ mRender = false;
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::setLooping(int loop)
+{
+ LOGV("setLooping\n");
+ Mutex::Autolock l(mMutex);
+ mLoop = (loop != 0);
+ return NO_ERROR;
+}
+
+status_t VorbisPlayer::createOutputTrack() {
+ // open audio track
+ vorbis_info *vi = ov_info(&mVorbisFile, -1);
+
+ LOGV("Create AudioTrack object: rate=%ld, channels=%d\n",
+ vi->rate, vi->channels);
+ if (mAudioSink->open(vi->rate, vi->channels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) {
+ LOGE("mAudioSink open failed");
+ return ERROR_OPEN_FAILED;
+ }
+ return NO_ERROR;
+}
+
+int VorbisPlayer::renderThread(void* p) {
+ return ((VorbisPlayer*)p)->render();
+}
+
+#define AUDIOBUFFER_SIZE 4096
+
+int VorbisPlayer::render() {
+ int result = -1;
+ int temp;
+ int current_section = 0;
+ bool audioStarted = false;
+
+ LOGV("render\n");
+
+ // allocate render buffer
+ mAudioBuffer = new char[AUDIOBUFFER_SIZE];
+ if (!mAudioBuffer) {
+ LOGE("mAudioBuffer allocate failed\n");
+ goto threadExit;
+ }
+
+ // let main thread know we're ready
+ {
+ Mutex::Autolock l(mMutex);
+ mRenderTid = myTid();
+ mCondition.signal();
+ }
+
+ while (1) {
+ long numread = 0;
+ {
+ Mutex::Autolock l(mMutex);
+
+ // pausing?
+ if (mPaused) {
+ if (mAudioSink->ready()) mAudioSink->pause();
+ mRender = false;
+ audioStarted = false;
+ }
+
+ // nothing to render, wait for client thread to wake us up
+ if (!mExit && !mRender) {
+ LOGV("render - signal wait\n");
+ mCondition.wait(mMutex);
+ LOGV("render - signal rx'd\n");
+ }
+ if (mExit) break;
+
+ // We could end up here if start() is called, and before we get a
+ // chance to run, the app calls stop() or reset(). Re-check render
+ // flag so we don't try to render in stop or reset state.
+ if (!mRender) continue;
+
+ // render vorbis data into the input buffer
+ numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
+ if (numread == 0) {
+ // end of file, do we need to loop?
+ // ...
+ if (mLoop || mAndroidLoop) {
+ ov_time_seek(&mVorbisFile, 0);
+ current_section = 0;
+ numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
+ } else {
+ 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);
+ LOGV("playback complete - signal rx'd");
+ if (mExit) break;
+
+ // if we're still at the end, restart from the beginning
+ if (mState == STATE_OPEN) {
+ int curpos = ov_time_tell(&mVorbisFile);
+ if (curpos == endpos) {
+ ov_time_seek(&mVorbisFile, 0);
+ }
+ current_section = 0;
+ numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
+ }
+ }
+ }
+ }
+
+ // codec returns negative number on error
+ if (numread < 0) {
+ LOGE("Error in Vorbis decoder");
+ sendEvent(MEDIA_ERROR);
+ break;
+ }
+
+ // create audio output track if necessary
+ if (!mAudioSink->ready()) {
+ LOGV("render - create output track\n");
+ if (createOutputTrack() != NO_ERROR)
+ break;
+ }
+
+ // Write data to the audio hardware
+ if ((temp = mAudioSink->write(mAudioBuffer, numread)) < 0) {
+ LOGE("Error in writing:%d",temp);
+ result = temp;
+ break;
+ }
+
+ // start audio output if necessary
+ if (!audioStarted && !mPaused && !mExit) {
+ LOGV("render - starting audio\n");
+ mAudioSink->start();
+ audioStarted = true;
+ }
+ }
+
+threadExit:
+ mAudioSink.clear();
+ if (mAudioBuffer) {
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+
+ // tell main thread goodbye
+ Mutex::Autolock l(mMutex);
+ mRenderTid = -1;
+ mCondition.signal();
+ return result;
+}
+
+} // end namespace android
diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h
new file mode 100644
index 0000000..c30dc1b
--- /dev/null
+++ b/media/libmediaplayerservice/VorbisPlayer.h
@@ -0,0 +1,91 @@
+/*
+**
+** Copyright 2008, 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_VORBISPLAYER_H
+#define ANDROID_VORBISPLAYER_H
+
+#include <utils/threads.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/AudioTrack.h>
+
+#include "ivorbiscodec.h"
+#include "ivorbisfile.h"
+
+#define ANDROID_LOOP_TAG "ANDROID_LOOP"
+
+namespace android {
+
+class VorbisPlayer : public MediaPlayerInterface {
+public:
+ VorbisPlayer();
+ ~VorbisPlayer();
+
+ virtual void onFirstRef();
+ virtual status_t initCheck();
+ 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; }
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t seekTo(int msec);
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t getCurrentPosition(int* msec);
+ virtual status_t getDuration(int* msec);
+ virtual status_t release();
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType() { return VORBIS_PLAYER; }
+
+private:
+ status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length);
+ status_t reset_nosync();
+ status_t createOutputTrack();
+ static int renderThread(void*);
+ int render();
+
+ static size_t vp_fread(void *, size_t, size_t, void *);
+ static int vp_fseek(void *, ogg_int64_t, int);
+ static int vp_fclose(void *);
+ static long vp_ftell(void *);
+
+ Mutex mMutex;
+ Condition mCondition;
+ FILE* mFile;
+ int64_t mOffset;
+ int64_t mLength;
+ OggVorbis_File mVorbisFile;
+ char* mAudioBuffer;
+ int mPlayTime;
+ int mDuration;
+ status_t mState;
+ int mStreamType;
+ bool mLoop;
+ bool mAndroidLoop;
+ volatile bool mExit;
+ bool mPaused;
+ volatile bool mRender;
+ pid_t mRenderTid;
+};
+
+}; // namespace android
+
+#endif // ANDROID_VORBISPLAYER_H
+
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
new file mode 100644
index 0000000..c681698
--- /dev/null
+++ b/media/mediaserver/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_mediaserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioflinger \
+ libcameraservice \
+ libmediaplayerservice \
+ libutils
+
+base := $(LOCAL_PATH)/../..
+
+LOCAL_C_INCLUDES := \
+ $(base)/libs/audioflinger \
+ $(base)/camera/libcameraservice \
+ $(base)/media/libmediaplayerservice
+
+LOCAL_MODULE:= mediaserver
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
new file mode 100644
index 0000000..6954b63
--- /dev/null
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+// System headers required for setgroups, etc.
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <AudioFlinger.h>
+#include <CameraService.h>
+#include <MediaPlayerService.h>
+#include <private/android_filesystem_config.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ LOGI("ServiceManager: %p", sm.get());
+ AudioFlinger::instantiate();
+ MediaPlayerService::instantiate();
+ CameraService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}