| /* |
| * Copyright (C) 2011 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 __AAH_RX_PLAYER_H__ |
| #define __AAH_RX_PLAYER_H__ |
| |
| #include <common_time/cc_helper.h> |
| #include <media/MediaPlayerInterface.h> |
| #include <media/stagefright/foundation/ADebug.h> |
| #include <media/stagefright/MediaBuffer.h> |
| #include <media/stagefright/MediaSource.h> |
| #include <media/stagefright/MetaData.h> |
| #include <media/stagefright/OMXClient.h> |
| #include <netinet/in.h> |
| #include <utils/KeyedVector.h> |
| #include <utils/LinearTransform.h> |
| #include <utils/threads.h> |
| |
| #include "aah_decoder_pump.h" |
| #include "pipe_event.h" |
| |
| namespace android { |
| |
| class AAH_RXPlayer : public MediaPlayerInterface { |
| public: |
| AAH_RXPlayer(); |
| |
| virtual status_t initCheck(); |
| virtual status_t setDataSource(const char *url, |
| const KeyedVector<String8, String8>* |
| headers); |
| virtual status_t setDataSource(int fd, int64_t offset, int64_t length); |
| virtual status_t setVideoSurface(const sp<Surface>& surface); |
| virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& |
| surfaceTexture); |
| 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(); |
| virtual status_t setParameter(int key, const Parcel &request); |
| virtual status_t getParameter(int key, Parcel *reply); |
| virtual status_t invoke(const Parcel& request, Parcel *reply); |
| |
| protected: |
| virtual ~AAH_RXPlayer(); |
| |
| private: |
| class ThreadWrapper : public Thread { |
| public: |
| friend class AAH_RXPlayer; |
| explicit ThreadWrapper(AAH_RXPlayer& player) |
| : Thread(false /* canCallJava */ ) |
| , player_(player) { } |
| |
| virtual bool threadLoop() { return player_.threadLoop(); } |
| |
| private: |
| AAH_RXPlayer& player_; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper); |
| }; |
| |
| #pragma pack(push, 1) |
| // PacketBuffers are structures used by the RX ring buffer. The ring buffer |
| // is a ring of pointers to PacketBuffer structures which act as variable |
| // length byte arrays and hold the contents of received UDP packets. Rather |
| // than make this a structure which hold a length and a pointer to another |
| // allocated structure (which would require two allocations), this struct |
| // uses a structure overlay pattern where allocation for the byte array |
| // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from |
| // whatever pool/heap the packet buffer pulls from, and then overlaying the |
| // packed PacketBuffer structure on top of the allocation. The one-byte |
| // array at the end of the structure serves as an offset to the the data |
| // portion of the allocation; packet buffers are never allocated on the |
| // stack or using the new operator. Instead, the static allocate-byte-array |
| // and destroy methods handle the allocate and overlay pattern. They also |
| // allow for a potential future optimization where instead of just |
| // allocating blocks from the process global heap and overlaying, the |
| // allocator is replaced with a different implementation (private heap, |
| // free-list, circular buffer, etc) which reduces potential heap |
| // fragmentation issues which might arise from the frequent allocation and |
| // destruction of the received UDP traffic. |
| struct PacketBuffer { |
| ssize_t length_; |
| uint8_t data_[1]; |
| |
| // TODO : consider changing this to be some form of ring buffer or free |
| // pool system instead of just using the heap in order to avoid heap |
| // fragmentation. |
| static PacketBuffer* allocate(ssize_t length); |
| static void destroy(PacketBuffer* pb); |
| |
| private: |
| // Force people to use allocate/destroy instead of new/delete. |
| PacketBuffer() { } |
| ~PacketBuffer() { } |
| }; |
| |
| struct RetransRequest { |
| uint32_t magic_; |
| uint32_t mcast_ip_; |
| uint16_t mcast_port_; |
| uint16_t start_seq_; |
| uint16_t end_seq_; |
| }; |
| #pragma pack(pop) |
| |
| enum GapStatus { |
| kGS_NoGap = 0, |
| kGS_NormalGap, |
| kGS_FastStartGap, |
| }; |
| |
| struct SeqNoGap { |
| uint16_t start_seq_; |
| uint16_t end_seq_; |
| }; |
| |
| class RXRingBuffer { |
| public: |
| explicit RXRingBuffer(uint32_t capacity); |
| ~RXRingBuffer(); |
| |
| bool initCheck() const { return (ring_ != NULL); } |
| void reset(); |
| |
| // Push a packet buffer with a given sequence number into the ring |
| // buffer. pushBuffer will always consume the buffer pushed to it, |
| // either destroying it because it was a duplicate or overflow, or |
| // holding on to it in the ring. Callers should not hold any references |
| // to PacketBuffers after they have been pushed to the ring. Returns |
| // false in the case of a serious error (such as ring overflow). |
| // Callers should consider resetting the pipeline entirely in the event |
| // of a serious error. |
| bool pushBuffer(PacketBuffer* buf, uint16_t seq); |
| |
| // Fetch the next buffer in the RTP sequence. Returns NULL if there is |
| // no buffer to fetch. If a non-NULL PacketBuffer is returned, |
| // is_discon will be set to indicate whether or not this PacketBuffer is |
| // discontiuous with any previously returned packet buffers. Packet |
| // buffers returned by fetchBuffer are the caller's responsibility; they |
| // must be certain to destroy the buffers when they are done. |
| PacketBuffer* fetchBuffer(bool* is_discon); |
| |
| // Returns true and fills out the gap structure if the read pointer of |
| // the ring buffer is currently pointing to a gap which would stall a |
| // fetchBuffer operation. Returns false if the read pointer is not |
| // pointing to a gap in the sequence currently. |
| GapStatus fetchCurrentGap(SeqNoGap* gap); |
| |
| // Causes the read pointer to skip over any portion of a gap indicated |
| // by nak. If nak is NULL, any gap currently blocking the read pointer |
| // will be completely skipped. If any portion of a gap is skipped, the |
| // next successful read from fetch buffer will indicate a discontinuity. |
| void processNAK(const SeqNoGap* nak = NULL); |
| |
| // Compute the number of milliseconds until the inactivity timer for |
| // this RTP stream. Returns -1 if there is no active timeout, or 0 if |
| // the system has already timed out. |
| int computeInactivityTimeout(); |
| |
| private: |
| Mutex lock_; |
| PacketBuffer** ring_; |
| uint32_t capacity_; |
| uint32_t rd_; |
| uint32_t wr_; |
| |
| uint16_t rd_seq_; |
| bool rd_seq_known_; |
| bool waiting_for_fast_start_; |
| bool fetched_first_packet_; |
| |
| uint64_t rtp_activity_timeout_; |
| bool rtp_activity_timeout_valid_; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer); |
| }; |
| |
| class Substream : public virtual RefBase { |
| public: |
| Substream(uint32_t ssrc, OMXClient& omx); |
| |
| void cleanupBufferInProgress(); |
| void shutdown(); |
| void processPayloadStart(uint8_t* buf, |
| uint32_t amt, |
| int32_t ts_lower); |
| void processPayloadCont (uint8_t* buf, |
| uint32_t amt); |
| void processTSTransform(const LinearTransform& trans); |
| |
| bool isAboutToUnderflow(); |
| uint32_t getSSRC() const { return ssrc_; } |
| uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; } |
| status_t getStatus() const { return status_; } |
| |
| protected: |
| virtual ~Substream(); |
| |
| private: |
| void cleanupDecoder(); |
| bool shouldAbort(const char* log_tag); |
| void processCompletedBuffer(); |
| bool setupSubstreamMeta(); |
| bool setupMP3SubstreamMeta(); |
| bool setupAACSubstreamMeta(); |
| bool setupSubstreamType(uint8_t substream_type, |
| uint8_t codec_type); |
| |
| uint32_t ssrc_; |
| bool waiting_for_rap_; |
| status_t status_; |
| |
| bool substream_details_known_; |
| uint8_t substream_type_; |
| uint8_t codec_type_; |
| const char* codec_mime_type_; |
| sp<MetaData> substream_meta_; |
| |
| MediaBuffer* buffer_in_progress_; |
| uint32_t expected_buffer_size_; |
| uint32_t buffer_filled_; |
| |
| Vector<uint8_t> aux_data_in_progress_; |
| uint32_t aux_data_expected_size_; |
| |
| sp<AAH_DecoderPump> decoder_; |
| |
| static int64_t kAboutToUnderflowThreshold; |
| |
| DISALLOW_EVIL_CONSTRUCTORS(Substream); |
| }; |
| |
| typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec; |
| |
| status_t startWorkThread(); |
| void stopWorkThread(); |
| virtual bool threadLoop(); |
| bool setupSocket(); |
| void cleanupSocket(); |
| void resetPipeline(); |
| void reset_l(); |
| bool processRX(PacketBuffer* pb); |
| void processRingBuffer(); |
| void processCommandPacket(PacketBuffer* pb); |
| bool processGaps(); |
| int computeNextGapRetransmitTimeout(); |
| void fetchAudioFlinger(); |
| |
| PipeEvent wakeup_work_thread_evt_; |
| sp<ThreadWrapper> thread_wrapper_; |
| Mutex api_lock_; |
| bool is_playing_; |
| bool data_source_set_; |
| |
| struct sockaddr_in listen_addr_; |
| int sock_fd_; |
| bool multicast_joined_; |
| |
| struct sockaddr_in transmitter_addr_; |
| bool transmitter_known_; |
| |
| uint32_t current_epoch_; |
| bool current_epoch_known_; |
| |
| SeqNoGap current_gap_; |
| GapStatus current_gap_status_; |
| uint64_t next_retrans_req_time_; |
| |
| RXRingBuffer ring_buffer_; |
| SubstreamVec substreams_; |
| OMXClient omx_; |
| CCHelper cc_helper_; |
| |
| // Connection to audio flinger used to hack a path to setMasterVolume. |
| sp<IAudioFlinger> audio_flinger_; |
| |
| static const uint32_t kRTPRingBufferSize; |
| static const uint32_t kRetransRequestMagic; |
| static const uint32_t kFastStartRequestMagic; |
| static const uint32_t kRetransNAKMagic; |
| static const uint32_t kGapRerequestTimeoutUSec; |
| static const uint32_t kFastStartTimeoutUSec; |
| static const uint32_t kRTPActivityTimeoutUSec; |
| |
| static const uint32_t INVOKE_GET_MASTER_VOLUME = 3; |
| static const uint32_t INVOKE_SET_MASTER_VOLUME = 4; |
| |
| static uint64_t monotonicUSecNow(); |
| |
| DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer); |
| }; |
| |
| } // namespace android |
| |
| #endif // __AAH_RX_PLAYER_H__ |