summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/chromium_http/support.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2011-03-08 15:59:28 -0800
committerAndreas Huber <andih@google.com>2011-03-09 10:14:46 -0800
commit1156dc913a5ba7b2bc86489468d4914430f03d14 (patch)
tree351803a481df1784b789fdcdfa13cbc9b30a0a12 /media/libstagefright/chromium_http/support.cpp
parent271151e65fdc289514317b6e4e1b8805e6c647e1 (diff)
downloadframeworks_av-1156dc913a5ba7b2bc86489468d4914430f03d14.zip
frameworks_av-1156dc913a5ba7b2bc86489468d4914430f03d14.tar.gz
frameworks_av-1156dc913a5ba7b2bc86489468d4914430f03d14.tar.bz2
An HTTP datasource for stagefright using the chromium code.
Use of this new datasource is now the default unless overwritten by adb shell setprop media.stagefright.use-chromium false Change-Id: I156a8eb9a1fff1cb537b4aec6cf3e8e6052be81e
Diffstat (limited to 'media/libstagefright/chromium_http/support.cpp')
-rw-r--r--media/libstagefright/chromium_http/support.cpp454
1 files changed, 454 insertions, 0 deletions
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
new file mode 100644
index 0000000..d1380f0
--- /dev/null
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ChromiumHTTPDataSourceSupport"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "support.h"
+
+#include "android/net/android_network_library_impl.h"
+#include "base/thread.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ssl_config_service.h"
+#include "net/http/http_cache.h"
+
+#include "include/ChromiumHTTPDataSource.h"
+
+#include <cutils/properties.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+static Mutex gNetworkThreadLock;
+static base::Thread *gNetworkThread = NULL;
+static scoped_refptr<URLRequestContext> gReqContext;
+
+static void InitializeNetworkThreadIfNecessary() {
+ Mutex::Autolock autoLock(gNetworkThreadLock);
+ if (gNetworkThread == NULL) {
+ gNetworkThread = new base::Thread("network");
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ CHECK(gNetworkThread->StartWithOptions(options));
+
+ gReqContext = new SfRequestContext;
+
+ net::AndroidNetworkLibrary::RegisterSharedInstance(
+ new SfNetworkLibrary);
+ }
+}
+
+static void MY_LOGI(const char *s) {
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s);
+}
+
+static void MY_LOGV(const char *s) {
+#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
+ LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s);
+#endif
+}
+
+SfNetLog::SfNetLog()
+ : mNextID(1) {
+}
+
+void SfNetLog::AddEntry(
+ EventType type,
+ const base::TimeTicks &time,
+ const Source &source,
+ EventPhase phase,
+ EventParameters *params) {
+#if 0
+ MY_LOGI(StringPrintf(
+ "AddEntry time=%s type=%s source=%s phase=%s\n",
+ TickCountToString(time).c_str(),
+ EventTypeToString(type),
+ SourceTypeToString(source.type),
+ EventPhaseToString(phase)).c_str());
+#endif
+}
+
+uint32 SfNetLog::NextID() {
+ return mNextID++;
+}
+
+net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
+ return LOG_ALL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfRequestContext::SfRequestContext() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ mUserAgent = ua.c_str();
+
+ net_log_ = new SfNetLog;
+
+ host_resolver_ =
+ net::CreateSystemHostResolver(
+ net::HostResolver::kDefaultParallelism,
+ NULL /* resolver_proc */,
+ net_log_);
+
+ ssl_config_service_ =
+ net::SSLConfigService::CreateSystemSSLConfigService();
+
+ proxy_service_ = net::ProxyService::CreateDirect();
+
+ http_transaction_factory_ = new net::HttpCache(
+ host_resolver_,
+ dnsrr_resolver_,
+ dns_cert_checker_.get(),
+ proxy_service_.get(),
+ ssl_config_service_.get(),
+ NULL, // http_auth_handler_factory
+ network_delegate_,
+ net_log_,
+ NULL); // backend_factory
+}
+
+const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
+ return mUserAgent;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfNetworkLibrary::SfNetworkLibrary() {}
+
+SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain(
+ const std::vector<std::string>& cert_chain,
+ const std::string& hostname,
+ const std::string& auth_type) {
+ return VERIFY_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SfDelegate::SfDelegate()
+ : mOwner(NULL),
+ mURLRequest(NULL),
+ mReadBuffer(new net::IOBufferWithSize(8192)),
+ mNumBytesRead(0),
+ mNumBytesTotal(0),
+ mDataDestination(NULL),
+ mAtEOS(false) {
+ InitializeNetworkThreadIfNecessary();
+}
+
+SfDelegate::~SfDelegate() {
+ CHECK(mURLRequest == NULL);
+}
+
+void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
+ mOwner = owner;
+}
+
+void SfDelegate::OnReceivedRedirect(
+ URLRequest *request, const GURL &new_url, bool *defer_redirect) {
+ MY_LOGI("OnReceivedRedirect");
+}
+
+void SfDelegate::OnAuthRequired(
+ URLRequest *request, net::AuthChallengeInfo *auth_info) {
+ MY_LOGI("OnAuthRequired");
+
+ inherited::OnAuthRequired(request, auth_info);
+}
+
+void SfDelegate::OnCertificateRequested(
+ URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
+ MY_LOGI("OnCertificateRequested");
+
+ inherited::OnCertificateRequested(request, cert_request_info);
+}
+
+void SfDelegate::OnSSLCertificateError(
+ URLRequest *request, int cert_error, net::X509Certificate *cert) {
+ fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error);
+
+ inherited::OnSSLCertificateError(request, cert_error, cert);
+}
+
+void SfDelegate::OnGetCookies(URLRequest *request, bool blocked_by_policy) {
+ MY_LOGI("OnGetCookies");
+}
+
+void SfDelegate::OnSetCookie(
+ URLRequest *request,
+ const std::string &cookie_line,
+ const net::CookieOptions &options,
+ bool blocked_by_policy) {
+ MY_LOGI("OnSetCookie");
+}
+
+void SfDelegate::OnResponseStarted(URLRequest *request) {
+ if (request->status().status() != URLRequestStatus::SUCCESS) {
+ MY_LOGI(StringPrintf(
+ "Request failed with status %d and os_error %d",
+ request->status().status(),
+ request->status().os_error()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(ERROR_IO);
+ return;
+ } else if (mRangeRequested && request->GetResponseCode() != 206) {
+ MY_LOGI(StringPrintf(
+ "We requested a content range, but server didn't "
+ "support that. (responded with %d)",
+ request->GetResponseCode()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(-EPIPE);
+ return;
+ } else if ((request->GetResponseCode() / 100) != 2) {
+ MY_LOGI(StringPrintf(
+ "Server responded with http status %d",
+ request->GetResponseCode()).c_str());
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onConnectionFailed(ERROR_IO);
+ return;
+ }
+
+ MY_LOGV("OnResponseStarted");
+
+ std::string headers;
+ request->GetAllResponseHeaders(&headers);
+
+ MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
+
+ mOwner->onConnectionEstablished(request->GetExpectedContentSize());
+}
+
+void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) {
+ if (bytes_read == -1) {
+ MY_LOGI(StringPrintf(
+ "OnReadCompleted, read failed, status %d",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ }
+
+ MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str());
+
+ if (bytes_read < 0) {
+ MY_LOGI(StringPrintf(
+ "Read failed w/ status %d\n",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ } else if (bytes_read == 0) {
+ mAtEOS = true;
+ mOwner->onReadCompleted(mNumBytesRead);
+ return;
+ }
+
+ CHECK_GT(bytes_read, 0);
+ CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal);
+
+ memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+ mReadBuffer->data(),
+ bytes_read);
+
+ mNumBytesRead += bytes_read;
+
+ readMore(request);
+}
+
+void SfDelegate::readMore(URLRequest *request) {
+ while (mNumBytesRead < mNumBytesTotal) {
+ size_t copy = mNumBytesTotal - mNumBytesRead;
+ if (copy > mReadBuffer->size()) {
+ copy = mReadBuffer->size();
+ }
+
+ int n;
+ if (request->Read(mReadBuffer, copy, &n)) {
+ MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str());
+
+ CHECK_LE((size_t)n, copy);
+
+ memcpy((uint8_t *)mDataDestination + mNumBytesRead,
+ mReadBuffer->data(),
+ n);
+
+ mNumBytesRead += n;
+
+ if (n == 0) {
+ mAtEOS = true;
+ break;
+ }
+ } else {
+ MY_LOGV("readMore pending read");
+
+ if (request->status().status() != URLRequestStatus::IO_PENDING) {
+ MY_LOGI(StringPrintf(
+ "Direct read failed w/ status %d\n",
+ request->status().status()).c_str());
+
+ mOwner->onReadCompleted(ERROR_IO);
+ return;
+ }
+
+ return;
+ }
+ }
+
+ mOwner->onReadCompleted(mNumBytesRead);
+}
+
+void SfDelegate::initiateConnection(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ GURL url(uri);
+
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateConnectionWrapper,
+ this,
+ url,
+ headers,
+ offset));
+
+}
+
+// static
+void SfDelegate::OnInitiateConnectionWrapper(
+ SfDelegate *me, GURL url,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset) {
+ me->onInitiateConnection(url, headers, offset);
+}
+
+void SfDelegate::onInitiateConnection(
+ const GURL &url,
+ const KeyedVector<String8, String8> *extra,
+ off64_t offset) {
+ CHECK(mURLRequest == NULL);
+
+ mURLRequest = new URLRequest(url, this);
+ mAtEOS = false;
+
+ mRangeRequested = false;
+
+ if (offset != 0 || extra != NULL) {
+ net::HttpRequestHeaders headers =
+ mURLRequest->extra_request_headers();
+
+ if (offset != 0) {
+ headers.AddHeaderFromString(
+ StringPrintf("Range: bytes=%lld-", offset).c_str());
+
+ mRangeRequested = true;
+ }
+
+ if (extra != NULL) {
+ for (size_t i = 0; i < extra->size(); ++i) {
+ AString s;
+ s.append(extra->keyAt(i).string());
+ s.append(": ");
+ s.append(extra->valueAt(i).string());
+
+ headers.AddHeaderFromString(s.c_str());
+ }
+ }
+
+ mURLRequest->SetExtraRequestHeaders(headers);
+ }
+
+ mURLRequest->set_context(gReqContext);
+
+ mURLRequest->Start();
+}
+
+void SfDelegate::initiateDisconnect() {
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateDisconnectWrapper, this));
+}
+
+// static
+void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) {
+ me->onInitiateDisconnect();
+}
+
+void SfDelegate::onInitiateDisconnect() {
+ mURLRequest->Cancel();
+
+ delete mURLRequest;
+ mURLRequest = NULL;
+
+ mOwner->onDisconnectComplete();
+}
+
+void SfDelegate::initiateRead(void *data, size_t size) {
+ MessageLoop *loop = gNetworkThread->message_loop();
+ loop->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(
+ &SfDelegate::OnInitiateReadWrapper, this, data, size));
+}
+
+// static
+void SfDelegate::OnInitiateReadWrapper(
+ SfDelegate *me, void *data, size_t size) {
+ me->onInitiateRead(data, size);
+}
+
+void SfDelegate::onInitiateRead(void *data, size_t size) {
+ CHECK(mURLRequest != NULL);
+
+ mNumBytesRead = 0;
+ mNumBytesTotal = size;
+ mDataDestination = data;
+
+ if (mAtEOS) {
+ mOwner->onReadCompleted(0);
+ return;
+ }
+
+ readMore(mURLRequest);
+}
+
+} // namespace android
+