Music Hub  ..
A session-wide music playback service
server.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Canonical Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
17  */
18 
19 #include <core/media/service.h>
20 #include <core/media/player.h>
21 #include <core/media/track_list.h>
22 
26 
27 #include <core/posix/signal.h>
28 
29 #include <iostream>
30 
31 namespace media = core::ubuntu::media;
32 
33 using namespace std;
34 
35 #if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER)
36 #include <hybris/media/media_codec_layer.h>
37 
38 namespace
39 {
40 void logger_init()
41 {
42  const char *level = ::getenv("MH_LOG_LEVEL");
43  // Default level is kInfo
44  media::Logger::Severity severity{media::Logger::Severity::kInfo};
45  if (level)
46  {
47  if (strcmp(level, "trace") == 0)
48  severity = media::Logger::Severity::kTrace;
49  else if (strcmp(level, "debug") == 0)
50  severity = media::Logger::Severity::kDebug;
51  else if (strcmp(level, "info") == 0)
52  severity = media::Logger::Severity::kInfo;
53  else if (strcmp(level, "warning") == 0)
54  severity = media::Logger::Severity::kWarning;
55  else if (strcmp(level, "error") == 0)
56  severity = media::Logger::Severity::kError;
57  else if (strcmp(level, "fatal") == 0)
58  severity = media::Logger::Severity::kFatal;
59  else
60  std::cerr << "Invalid log level \"" << level
61  << "\", setting to info. Valid options: [trace, debug, info, warning, error, fatal]."
62  << std::endl;
63  }
64  else
65  std::cout << "Using default log level: info" << std::endl;
66 
67  media::Log().Init(severity);
68  cout << "Log level: " << severity << std::endl;
69 }
70 
71 // All platform-specific initialization routines go here.
72 void platform_init()
73 {
75  switch (b)
76  {
77  case media::AVBackend::Backend::hybris:
78  MH_DEBUG("Found hybris backend");
79  decoding_service_init();
80  break;
81  case media::AVBackend::Backend::none:
82  MH_WARNING("No video backend selected. Video functionality won't work.");
83  break;
84  default:
85  MH_INFO("Invalid or no A/V backend specified, using \"hybris\" as a default.");
86  decoding_service_init();
87  }
88 }
89 }
90 #else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER
91 namespace
92 {
93 // All platform-specific initialization routines go here.
94 void platform_init()
95 {
96  // Consciously left empty
97 }
98 }
99 #endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER
100 
101 int main()
102 {
103  auto trap = core::posix::trap_signals_for_all_subsequent_threads(
104  {
105  core::posix::Signal::sig_int,
106  core::posix::Signal::sig_term
107  });
108 
109  trap->signal_raised().connect([trap](core::posix::Signal)
110  {
111  trap->stop();
112  });
113 
114  logger_init();
115 
116  // Init platform-specific functionality.
117  platform_init();
118 
119  // We keep track of our state.
120  bool shutdown_requested{false};
121 
122  // Our helper for connecting to external services.
124 
125  // We move communication with all external services to its own worker thread
126  // to keep the actual service thread free from such operations.
127  std::thread external_services_worker
128  {
129  // We keep on running until shutdown has been explicitly requested.
130  // All exceptions thrown on this thread are caught, and reported to
131  // the terminal for post-mortem debugging purposes.
132  [&shutdown_requested, &external_services]()
133  {
134  while (not shutdown_requested)
135  {
136  try
137  {
138  // Blocking call to the underlying reactor implementation.
139  // Only returns cleanly when explicitly stopped.
140  external_services.io_service.run();
141  }
142  catch (const std::exception& e)
143  {
144  std::cerr << "Error while executing the underlying io_service: " << e.what() << std::endl;
145  }
146  catch (...)
147  {
148  std::cerr << "Error while executing the underlying io_service." << std::endl;
149  }
150  }
151  }
152  };
153 
154  // Our common player store instance for tracking player instances.
155  auto player_store = std::make_shared<media::HashedKeyedPlayerStore>();
156  // We assemble the configuration for executing the service now.
157  media::ServiceImplementation::Configuration service_config
158  {
159  std::make_shared<media::HashedKeyedPlayerStore>(),
160  external_services
161  };
162 
163  auto impl = std::make_shared<media::ServiceImplementation>(media::ServiceImplementation::Configuration
164  {
165  player_store,
166  external_services
167  });
168 
169  auto skeleton = std::make_shared<media::ServiceSkeleton>(media::ServiceSkeleton::Configuration
170  {
171  impl,
172  player_store,
173  external_services
174  });
175 
176  std::thread service_worker
177  {
178  [&shutdown_requested, skeleton]()
179  {
180  while (not shutdown_requested)
181  {
182  try
183  {
184  skeleton->run();
185  }
186  catch (const std::exception& e)
187  {
188  std::cerr << "Recoverable error while executing the service: " << e.what() << std::endl;
189  }
190  catch (...)
191  {
192  std::cerr << "Recoverable error while executing the service." << std::endl;
193  }
194  }
195  }
196  };
197 
198  // We block on waiting for signals telling us to gracefully shutdown.
199  // Incoming signals are handled in a lambda connected to signal_raised()
200  // which is setup at the beginning of main(...).
201  trap->run();
202 
203  // Inform our workers that we should shutdown gracefully
204  shutdown_requested = true;
205 
206  // And stop execution of helper and actual service.
207  skeleton->stop();
208 
209  if (service_worker.joinable())
210  service_worker.join();
211 
212  external_services.stop();
213 
214  if (external_services_worker.joinable())
215  external_services_worker.join();
216 
217  return 0;
218 }
Logger & Log()
Definition: logger.cpp:151
virtual void Init(const core::ubuntu::media::Logger::Severity &severity=core::ubuntu::media::Logger::Severity::kWarning)=0
#define MH_INFO(...)
Definition: logger.h:125
STL namespace.
#define MH_DEBUG(...)
Definition: logger.h:123
#define MH_WARNING(...)
Definition: logger.h:127
static Backend get_backend_type()
Returns the type of audio/video decoding/encoding backend being used.
Definition: backend.cpp:26
int main()
Definition: server.cpp:101