1 /*
2  * This file is part of Wireless Display Software for Linux OS
3  *
4  * Copyright (C) 2014 Intel Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21 
22 #include "libwds/public/sink.h"
23 
24 #include "libwds/common/message_handler.h"
25 #include "libwds/common/rtsp_input_handler.h"
26 #include "libwds/public/wds_export.h"
27 #include "libwds/rtsp/pause.h"
28 #include "libwds/rtsp/play.h"
29 #include "libwds/rtsp/teardown.h"
30 #include "libwds/rtsp/triggermethod.h"
31 #include "libwds/public/media_manager.h"
32 #include "libwds/sink/cap_negotiation_state.h"
33 #include "libwds/sink/init_state.h"
34 #include "libwds/sink/session_state.h"
35 #include "libwds/sink/streaming_state.h"
36 
37 namespace wds {
38 using rtsp::Message;
39 using rtsp::Request;
40 using rtsp::Reply;
41 
42 namespace {
43 
44 // todo: check mandatory parameters for each message
InitializeRequestId(Request * request)45 bool InitializeRequestId(Request* request) {
46   Request::ID id = Request::UNKNOWN;
47   switch(request->method()) {
48   case Request::MethodOptions:
49     id = Request::M1;
50     break;
51   case Request::MethodGetParameter:
52     if (auto payload = rtsp::ToGetParameterPayload(request->payload())) {
53       if (!payload->properties().empty())
54         id = Request::M3;
55     } else {
56       id = Request::M16;
57     }
58     break;
59   case Request::MethodSetParameter:
60     if (auto payload = rtsp::ToPropertyMapPayload(request->payload())) {
61       if (payload->HasProperty(rtsp::PresentationURLPropertyType))
62         id = Request::M4;
63       else if (payload->HasProperty(rtsp::AVFormatChangeTimingPropertyType))
64         id = Request::M4;
65       else if (payload->HasProperty(rtsp::TriggerMethodPropertyType))
66         id = Request::M5;
67       break;
68     }
69   default:
70     WDS_ERROR("Failed to identify the received message");
71     return false;
72   }
73 
74   request->set_id(id);
75   return true;
76 }
77 
78 }
79 
80 class SinkStateMachine : public MessageSequenceHandler {
81  public:
SinkStateMachine(const InitParams & init_params)82    SinkStateMachine(const InitParams& init_params)
83      : MessageSequenceHandler(init_params),
84        keep_alive_timer_(0) {
85      auto m6_handler = make_ptr(new sink::M6Handler(init_params, keep_alive_timer_));
86      auto m16_handler = make_ptr(new sink::M16Handler(init_params, keep_alive_timer_));
87      AddSequencedHandler(make_ptr(new sink::InitState(init_params)));
88      AddSequencedHandler(make_ptr(new sink::CapNegotiationState(init_params)));
89      AddSequencedHandler(make_ptr(new sink::SessionState(init_params, m6_handler, m16_handler)));
90      AddSequencedHandler(make_ptr(new sink::StreamingState(init_params, m16_handler)));
91    }
92 
SinkStateMachine(Peer::Delegate * sender,SinkMediaManager * mng)93    SinkStateMachine(Peer::Delegate* sender, SinkMediaManager* mng)
94      : SinkStateMachine({sender, mng, this}) {}
95 
96  private:
97    unsigned keep_alive_timer_;
98 };
99 
100 class SinkImpl final : public Sink, public RTSPInputHandler, public MessageHandler::Observer {
101  public:
102   SinkImpl(Delegate* delegate, SinkMediaManager* mng);
103 
104  private:
105   // Sink implementation.
106   void Start() override;
107   void Reset() override;
108   void RTSPDataReceived(const std::string& message) override;
109   bool Teardown() override;
110   bool Play() override;
111   bool Pause() override;
112 
113   // RTSPInputHandler
114   void MessageParsed(std::unique_ptr<Message> message) override;
115 
116   // public MessageHandler::Observer
117   void OnCompleted(MessageHandlerPtr handler) override;
118   void OnError(MessageHandlerPtr handler) override;
119   void OnTimerEvent(unsigned timer_id) override;
120 
121   bool HandleCommand(std::unique_ptr<Message> command);
122 
123   template <class WfdMessage, Request::ID id>
124   std::unique_ptr<Message> CreateCommand();
125 
126   void ResetAndTeardownMedia();
127 
128   std::shared_ptr<SinkStateMachine> state_machine_;
129   Delegate* delegate_;
130   SinkMediaManager* manager_;
131 };
132 
SinkImpl(Delegate * delegate,SinkMediaManager * mng)133 SinkImpl::SinkImpl(Delegate* delegate, SinkMediaManager* mng)
134   : state_machine_(new SinkStateMachine({delegate, mng, this})),
135     delegate_(delegate),
136     manager_(mng) {
137 }
138 
Start()139 void SinkImpl::Start() {
140   state_machine_->Start();
141 }
142 
Reset()143 void SinkImpl::Reset() {
144   state_machine_->Reset();
145 }
146 
RTSPDataReceived(const std::string & message)147 void SinkImpl::RTSPDataReceived(const std::string& message) {
148   AddInput(message);
149 }
150 
151 template <class WfdMessage, Request::ID id>
CreateCommand()152 std::unique_ptr<Message> SinkImpl::CreateCommand() {
153   auto message = new WfdMessage(manager_->GetPresentationUrl());
154   message->header().set_session(manager_->GetSessionId());
155   message->header().set_cseq(delegate_->GetNextCSeq());
156   message->set_id(id);
157   return std::unique_ptr<Message>(message);
158 }
159 
HandleCommand(std::unique_ptr<Message> command)160 bool SinkImpl::HandleCommand(std::unique_ptr<Message> command) {
161   if (manager_->GetSessionId().empty() ||
162       manager_->GetPresentationUrl().empty())
163     return false;
164 
165   if (!state_machine_->CanSend(command.get()))
166     return false;
167   state_machine_->Send(std::move(command));
168   return true;
169 }
170 
Teardown()171 bool SinkImpl::Teardown() {
172   return HandleCommand(CreateCommand<rtsp::Teardown, Request::M8>());
173 }
174 
Play()175 bool SinkImpl::Play() {
176   return HandleCommand(CreateCommand<rtsp::Play, Request::M7>());
177 }
178 
Pause()179 bool SinkImpl::Pause() {
180   return HandleCommand(CreateCommand<rtsp::Pause, Request::M9>());
181 }
182 
MessageParsed(std::unique_ptr<Message> message)183 void SinkImpl::MessageParsed(std::unique_ptr<Message> message) {
184   if (message->is_request() && !InitializeRequestId(ToRequest(message.get()))) {
185     WDS_ERROR("Cannot identify the received message");
186     return;
187   }
188   if (!state_machine_->CanHandle(message.get())) {
189     WDS_ERROR("Cannot handle the received message with Id: %d", ToRequest(message.get())->id());
190     return;
191   }
192   state_machine_->Handle(std::move(message));
193 }
194 
ResetAndTeardownMedia()195 void SinkImpl::ResetAndTeardownMedia() {
196   manager_->Teardown();
197   state_machine_->Reset();
198 }
199 
OnCompleted(MessageHandlerPtr handler)200 void SinkImpl::OnCompleted(MessageHandlerPtr handler) {
201   assert(handler == state_machine_);
202   ResetAndTeardownMedia();
203 }
204 
OnError(MessageHandlerPtr handler)205 void SinkImpl::OnError(MessageHandlerPtr handler) {
206    assert(handler == state_machine_);
207    ResetAndTeardownMedia();
208 }
209 
OnTimerEvent(unsigned timer_id)210 void SinkImpl::OnTimerEvent(unsigned timer_id) {
211   if (state_machine_->HandleTimeoutEvent(timer_id))
212     state_machine_->Reset();
213 }
214 
Create(Delegate * delegate,SinkMediaManager * mng)215 Sink* Sink::Create(Delegate* delegate, SinkMediaManager* mng) {
216   return new SinkImpl(delegate, mng);
217 }
218 
219 }  // namespace wds
220