summaryrefslogtreecommitdiffstats
path: root/media/libaah_rtp/aah_rx_player.h
blob: ba5617eb7daedd2b2a8148041ad9f04f0f305766 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
 * 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__