aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/Networking/SampleNetPipeReader.cpp
blob: 4332cbd2872ceb4d56b96711d0891987c2d0d9d5 (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
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkGPipe.h"
#include "SkSockets.h"
#include "SkOSMenu.h"

/**
 * A simple networked pipe reader
 *
 * This view will connect to a user specified server, in this case meaning any
 * Skia app that's has a SkTCPServer set up to broadcast its piped drawing data,
 * received all the data transmitted and attempt to reproduce the drawing calls.
 * This reader will only keep the latest batch of data. In order to keep up with
 * the server, which may be producing data at a much higher rate than the reader
 * is consuming, the reader will attempt multiple reads and only render the
 * latest frame. this behavior can be adjusted by changing MAX_READS_PER_FRAME
 * or disabled by setting fSync to false
 */

#define MAX_READS_PER_FRAME 12

class NetPipeReaderView : public SampleView {
public:
    NetPipeReaderView() {
        fSocket = NULL;
        fSync = true;
    }

    ~NetPipeReaderView() {
        if (fSocket) {
            delete fSocket;
        }
        fDataArray.reset();
    }
    virtual void requestMenu(SkOSMenu* menu) {
        menu->setTitle("Net Pipe Reader");
        menu->appendTextField("Server IP", "Server IP", this->getSinkID(),
                              "IP address");
        menu->appendSwitch("Sync", "Sync", this->getSinkID(), fSync);
    }

protected:
    static void readData(int cid, const void* data, size_t size,
                         SkSocket::DataType type, void* context) {
        NetPipeReaderView* view = (NetPipeReaderView*)context;
        view->onRead(data, size);
    }

    void onRead(const void* data, size_t size) {
        if (size > 0)
            fDataArray.append(size, (const char*)data);
    }

    bool onQuery(SkEvent* evt) {
        if (SampleCode::TitleQ(*evt)) {
            SampleCode::TitleR(evt, "Net Pipe Reader");
            return true;
        }
        return this->INHERITED::onQuery(evt);
    }

    bool onEvent(const SkEvent& evt) {
        SkString s;
        if (SkOSMenu::FindText(evt, "Server IP", &s)) {
            if (NULL != fSocket) {
                delete fSocket;
            }
            fSocket = new SkTCPClient(s.c_str());
            fSocket->connectToServer();
            SkDebugf("Connecting to %s\n", s.c_str());
            return true;
        }
        if (SkOSMenu::FindSwitchState(evt, "Sync", &fSync))
            return true;
        return this->INHERITED::onEvent(evt);
    }

    void onDrawContent(SkCanvas* canvas) {
        if (NULL == fSocket)
            return;

        if (fSocket->isConnected()) {
            int dataToRemove = fDataArray.count();
            if (fSync) {
                int numreads = 0;
                while (fSocket->readPacket(readData, this) > 0 &&
                       numreads < MAX_READS_PER_FRAME) {
                    // at this point, new data has been read and stored, discard
                    // old data since it's not needed anymore
                    SkASSERT(fDataArray.count() > dataToRemove);
                    fDataArray.remove(0, dataToRemove);
                    dataToRemove = fDataArray.count();
                    ++numreads;
                }
                // clean up if max reads reached
                if (numreads == MAX_READS_PER_FRAME &&
                    fDataArray.count() > dataToRemove)
                    fDataArray.remove(0, dataToRemove);
            }
            else {
                if (fSocket->readPacket(readData, this) > 0)
                    fDataArray.remove(0, dataToRemove);
            }
        }
        else
            fSocket->connectToServer();

        SkGPipeReader reader(canvas);
        size_t bytesRead;
        SkGPipeReader::Status fStatus = reader.playback(fDataArray.begin(),
                                                        fDataArray.count(),
                                                        &bytesRead);
        SkASSERT(SkGPipeReader::kError_Status != fStatus);
        this->inval(NULL);
    }

private:
    bool fSync;
    SkTDArray<char> fDataArray;
    SkTCPClient* fSocket;
    typedef SampleView INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory() { return new NetPipeReaderView; }
static SkViewRegister reg(MyFactory);