root/trunk/whisperer/stream_server.cc

Revision 7, 5.9 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Mihai Ianculescu
31
32 #include <whisperlib/common/base/common.h>
33 #include "stream_server.h"
34
35 #include "stream_manager.h"
36
37 // our namespace
38 using namespace media;
39
40 StreamServer::StreamServer(StreamManager* manager,
41                            http::Server* http_server,
42                            const char* streaming_root) :
43   manager_(manager),
44   http_server_(http_server),
45   root_((streaming_root == NULL) ? "" : streaming_root) {
46   CHECK_NOT_NULL(manager_);
47   CHECK_NOT_NULL(http_server_);
48
49   http_server_->RegisterProcessor(
50     root_, NewPermanentCallback(this, &StreamServer::CreateCallback), true);
51 }
52
53 StreamServer::~StreamServer() {
54   http_server_->UnregisterProcessor(root_);
55 }
56
57 void StreamServer::CreateCallback(http::ServerRequest* request) {
58   URL* const url = request->request()->url();
59   CHECK_NOT_NULL(url);
60   DLOG_DEBUG << "Creating encoder for '" << url->spec() << "'.";
61
62   const string url_path(
63     url->UrlUnescape(url->path().c_str(), url->path().size()));
64
65   // no caching, ever
66   request->request()->server_header()->AddField(
67       "Cache-Control", "no-cache, must-revalidate, max-age=0", true);
68
69   // check the method, we only accept GET
70   if (request->request()->client_header()->method() != http::METHOD_GET) {
71     request->ReplyWithStatus(http::METHOD_NOT_ALLOWED);
72     return;
73   }
74
75   static const string root = root_ + "/";
76   if (!strutil::StrPrefix(url_path.c_str(), root.c_str())) {
77     request->ReplyWithStatus(http::NOT_FOUND);
78     return;
79   }
80
81   bool relay;
82   bool wrapped;
83   media::Stream::Type encoder_type;
84   media::Encoder::Audio::Params audio_params;
85   media::Encoder::Video::Params video_params;
86   int audio_port;
87   int video_port;
88   if (!StreamManager::ParseQueryString(
89         *url, relay, wrapped, encoder_type, audio_params, video_params,
90         audio_port, video_port)) {
91     request->ReplyWithStatus(http::BAD_REQUEST);
92     return;
93   }
94
95   // run the request
96   manager_->RunRequest(new ServerRequest(request),
97                        url_path.substr(root.length()).c_str(),
98                        relay,
99                        wrapped,
100                        encoder_type,
101                        &audio_params, &video_params,
102                        audio_port, video_port);
103 }
104
105 // Implementation of StreamServer::ServerRequest
106
107 void StreamServer::ServerRequest::Start() {
108   http::Header* const hs = request_->request()->server_header();
109   if (wrapped_) {
110     hs->AddField(http::kHeaderContentType, streaming::kInternalMimeType, true);
111   } else {
112     hs->AddField(http::kHeaderContentType, mime_type_.c_str(), true);
113   }
114
115   request_->BeginStreamingData(http::OK,
116       NewCallback(this, &StreamServer::ServerRequest::RequestProcess),
117       NewCallback(this, &StreamServer::ServerRequest::RequestClose));
118 }
119 void StreamServer::ServerRequest::Fail(http::HttpReturnCode result) {
120   request_->ReplyWithStatus(result);
121   selector_->DeleteInSelectLoop(this);
122 }
123
124 void StreamServer::ServerRequest::ReaderProcess(io::MemoryStream* inbuf) {
125   RequestProcess();
126 }
127 void StreamServer::ServerRequest::ReaderClose() {
128   DLOG_DEBUG << "Filereader closed for '"
129              << request_->request()->url()->spec() << "'";
130   selector_->DeleteInSelectLoop(reader_);
131   reader_ = NULL;
132
133   if (request_valid_) {
134     request_valid_ = false;
135     request_->EndStreamingData();
136     return;
137   }
138   selector_->DeleteInSelectLoop(this);
139 }
140
141 void StreamServer::ServerRequest::RequestProcess() {
142   CHECK_NOT_NULL(request_);
143   if (request_->is_orphaned()) {
144     if (reader_ != NULL) {
145       reader_->Close();
146     }
147     return;
148   }
149
150   CHECK_NOT_NULL(reader_);
151
152   int32 available_out;
153   available_out = request_->free_output_bytes();
154
155   CHECK_NOT_NULL(processor_);
156
157   bool send_frame;
158   if (!processor_->Process(request_->request()->server_data(),
159                            reader_->inbuf(), available_out, send_frame)) {
160     LOG_ERROR << "The processor returned failure for "
161               << request_->request()->url()->spec()
162               << "', terminating the request.";
163     reader_->Close();
164     return;
165   }
166
167   if (send_frame) {
168     request_->ContinueStreamingData(
169       NewCallback(this, &StreamServer::ServerRequest::RequestProcess));
170   }
171 }
172 void StreamServer::ServerRequest::RequestClose() {
173   DLOG_DEBUG << "Request closed for '"
174              << request_->request()->url()->spec() << "'.";
175   if (request_valid_) {
176     request_valid_ = false;
177     request_->EndStreamingData();
178   }
179
180   if (reader_ != NULL) {
181     reader_->Close();
182     return;
183   }
184   selector_->DeleteInSelectLoop(this);
185 }
Note: See TracBrowser for help on using the browser.