MediaStreamFrameController.cpp [plain text]
#include "config.h"
#include "MediaStreamFrameController.h"
#if ENABLE(MEDIA_STREAM)
#include "DOMWindow.h"
#include "Document.h"
#include "Frame.h"
#include "MediaStreamController.h"
#include "NavigatorUserMediaErrorCallback.h"
#include "NavigatorUserMediaSuccessCallback.h"
#include "Page.h"
#include "SecurityOrigin.h"
#include <wtf/RefCounted.h>
namespace WebCore {
class MediaStreamFrameController::Request : public RefCounted<Request> {
WTF_MAKE_NONCOPYABLE(Request);
public:
Request(ScriptExecutionContext* scriptExecutionContext)
: m_scriptExecutionContext(scriptExecutionContext) { }
virtual ~Request() { }
ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext; }
virtual bool isGenerateStreamRequest() const { return false; }
virtual bool isRecordedDataRequest() const { return false; }
virtual void abort() = 0;
private:
ScriptExecutionContext* m_scriptExecutionContext;
};
class MediaStreamFrameController::GenerateStreamRequest : public Request {
WTF_MAKE_NONCOPYABLE(GenerateStreamRequest);
public:
GenerateStreamRequest(ScriptExecutionContext* scriptExecutionContext,
PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback,
PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback)
: Request(scriptExecutionContext)
, m_successCallback(successCallback)
, m_errorCallback(errorCallback) { }
virtual ~GenerateStreamRequest() { }
virtual bool isGenerateStreamRequest() const { return true; }
virtual void abort()
{
if (m_errorCallback) {
RefPtr<NavigatorUserMediaError> error = adoptRef(new NavigatorUserMediaError(NavigatorUserMediaError::PERMISSION_DENIED));
m_errorCallback->scheduleCallback(scriptExecutionContext(), error);
}
}
PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback() const { return m_successCallback; }
PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback() const { return m_errorCallback; }
private:
RefPtr<NavigatorUserMediaSuccessCallback> m_successCallback;
RefPtr<NavigatorUserMediaErrorCallback> m_errorCallback;
};
void MediaStreamFrameController::RequestMap::abort(int requestId)
{
get(requestId)->abort();
remove(requestId);
}
void MediaStreamFrameController::RequestMap::abortAll()
{
while (!isEmpty()) {
begin()->second->abort();
remove(begin());
}
}
template <typename T>
void MediaStreamFrameController::ClientMapBase<T>::unregisterAll()
{
while (!this->isEmpty()) {
T key = this->begin()->first;
this->begin()->second->unregister();
ASSERT_UNUSED(key, !this->contains(key));
}
}
template <typename T>
void MediaStreamFrameController::ClientMapBase<T>::detachEmbedder()
{
for (typename MapType::iterator it = this->begin(); it != this->end(); ++it)
it->second->detachEmbedder();
}
MediaStreamFrameController::MediaStreamFrameController(Frame* frame)
: m_frame(frame)
, m_isInDetachedState(false)
{
if (!isClientAvailable())
enterDetachedState();
}
MediaStreamFrameController::~MediaStreamFrameController()
{
}
SecurityOrigin* MediaStreamFrameController::securityOrigin() const
{
return m_frame ? m_frame->existingDOMWindow()->securityOrigin() : 0;
}
ScriptExecutionContext* MediaStreamFrameController::scriptExecutionContext() const
{
return m_frame ? m_frame->existingDOMWindow()->scriptExecutionContext() : 0;
}
MediaStreamController* MediaStreamFrameController::pageController() const
{
return m_frame && m_frame->page() ? m_frame->page()->mediaStreamController() : 0;
}
void MediaStreamFrameController::unregister(StreamClient* client)
{
ASSERT(m_streams.contains(client->clientId()));
m_streams.remove(client->clientId());
}
void MediaStreamFrameController::enterDetachedState()
{
if (m_isInDetachedState) {
ASSERT(m_requests.isEmpty());
return;
}
m_requests.abortAll();
m_streams.detachEmbedder();
m_isInDetachedState = true;
}
bool MediaStreamFrameController::isClientAvailable() const
{
if (m_isInDetachedState)
return false;
MediaStreamController* controller = pageController();
return controller && controller->isClientAvailable();
}
void MediaStreamFrameController::disconnectPage()
{
if (pageController())
pageController()->unregisterFrameController(this);
enterDetachedState();
}
void MediaStreamFrameController::disconnectFrame()
{
disconnectPage();
ASSERT(m_requests.isEmpty());
m_streams.unregisterAll();
m_frame = 0;
}
void MediaStreamFrameController::transferToNewPage(Page*)
{
disconnectPage();
}
GenerateStreamOptionFlags MediaStreamFrameController::parseGenerateStreamOptions(const String& options)
{
GenerateStreamOptionFlags flags = 0;
Vector<String> optionList;
options.split(',', optionList);
for (Vector<String>::const_iterator option = optionList.begin(); option != optionList.end(); ++option) {
Vector<String> suboptionList;
option->split(' ', suboptionList);
if (suboptionList.first() == "audio")
flags |= GenerateStreamRequestAudio;
else if (suboptionList.first() == "video") {
bool videoSuboptions = false;
Vector<String>::const_iterator suboption = suboptionList.begin();
for (++suboption; suboption != suboptionList.end(); ++suboption)
if (*suboption == "user") {
flags |= GenerateStreamRequestVideoFacingUser;
videoSuboptions = true;
} else if (*suboption == "environment") {
flags |= GenerateStreamRequestVideoFacingEnvironment;
videoSuboptions = true;
}
if (!videoSuboptions)
flags |= GenerateStreamRequestVideoFacingUser | GenerateStreamRequestVideoFacingEnvironment;
}
}
return flags;
}
void MediaStreamFrameController::generateStream(const String& options,
PassRefPtr<NavigatorUserMediaSuccessCallback> successCallback,
PassRefPtr<NavigatorUserMediaErrorCallback> errorCallback,
ExceptionCode& ec)
{
ec = 0;
if (!successCallback)
return;
GenerateStreamOptionFlags flags = parseGenerateStreamOptions(options);
if (!flags) {
ec = NOT_SUPPORTED_ERR;
return;
}
int requestId = m_requests.getNextId();
m_requests.add(requestId, adoptRef(new GenerateStreamRequest(scriptExecutionContext(), successCallback, errorCallback)));
if (!isClientAvailable()) {
m_requests.abort(requestId);
return;
}
pageController()->generateStream(this, requestId, flags, securityOrigin());
}
void MediaStreamFrameController::streamGenerated(int requestId, const String& label)
{
if (m_requests.contains(requestId)) {
ASSERT(m_requests.get(requestId)->isGenerateStreamRequest());
ASSERT(!label.isNull());
m_requests.remove(requestId);
}
}
void MediaStreamFrameController::streamGenerationFailed(int requestId, NavigatorUserMediaError::ErrorCode code)
{
if (m_requests.contains(requestId)) {
ASSERT(m_requests.get(requestId)->isGenerateStreamRequest());
RefPtr<GenerateStreamRequest> streamRequest = static_cast<GenerateStreamRequest*>(m_requests.get(requestId).get());
m_requests.remove(requestId);
if (streamRequest->errorCallback()) {
RefPtr<NavigatorUserMediaError> error = adoptRef(new NavigatorUserMediaError(code));
streamRequest->errorCallback()->handleEvent(error.get());
}
}
}
}
#endif // ENABLE(MEDIA_STREAM)