Merge pull request #3819 from arnova/subtitles_for_stacks
[vuplus_xbmc] / xbmc / cores / AudioEngine / AESinkFactory.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "AESinkFactory.h"
22 #include "Interfaces/AESink.h"
23 #if defined(TARGET_WINDOWS)
24   #include "Sinks/AESinkWASAPI.h"
25   #include "Sinks/AESinkDirectSound.h"
26 #elif defined(TARGET_ANDROID)
27   #include "Sinks/AESinkAUDIOTRACK.h"
28 #elif defined(TARGET_RASPBERRY_PI)
29   #include "Sinks/AESinkPi.h"
30 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
31   #if defined(HAS_ALSA)
32     #include "Sinks/AESinkALSA.h"
33   #endif
34   #if defined(HAS_PULSEAUDIO)
35     #include "Sinks/AESinkPULSE.h"
36   #endif
37   #include "Sinks/AESinkOSS.h"
38 #else
39   #pragma message("NOTICE: No audio sink for target platform.  Audio output will not be available.")
40 #endif
41 #include "Sinks/AESinkProfiler.h"
42 #include "Sinks/AESinkNULL.h"
43
44 #include "settings/AdvancedSettings.h"
45 #include "utils/SystemInfo.h"
46 #include "utils/log.h"
47
48 void CAESinkFactory::ParseDevice(std::string &device, std::string &driver)
49 {
50   int pos = device.find_first_of(':');
51   if (pos > 0)
52   {
53     driver = device.substr(0, pos);
54     std::transform(driver.begin(), driver.end(), driver.begin(), ::toupper);
55
56     // check that it is a valid driver name
57     if (
58 #if defined(TARGET_WINDOWS)
59         driver == "WASAPI"      ||
60         driver == "DIRECTSOUND" ||
61 #elif defined(TARGET_ANDROID)
62         driver == "AUDIOTRACK"  ||
63 #elif defined(TARGET_RASPBERRY_PI)
64         driver == "PI"          ||
65 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
66   #if defined(HAS_ALSA)
67         driver == "ALSA"        ||
68   #endif
69   #if defined(HAS_PULSEAUDIO)
70         driver == "PULSE"       ||
71   #endif
72         driver == "OSS"         ||
73 #endif
74         driver == "PROFILER"    ||
75         driver == "NULL")
76       device = device.substr(pos + 1, device.length() - pos - 1);
77     else
78       driver.clear();
79   }
80   else
81     driver.clear();
82 }
83
84 IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAudioFormat &format)
85 {
86   IAESink *sink = NULL;
87
88   if (driver == "NULL")
89     sink = new CAESinkNULL();
90
91 #if defined(TARGET_WINDOWS)
92   else if (driver == "WASAPI")
93     sink = new CAESinkWASAPI();
94   else if (driver == "DIRECTSOUND")
95     sink = new CAESinkDirectSound();
96 #elif defined(TARGET_ANDROID)
97   sink = new CAESinkAUDIOTRACK();
98 #elif defined(TARGET_RASPBERRY_PI)
99   sink = new CAESinkPi();
100 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
101   #if defined(HAS_PULSEAUDIO)
102   else if (driver == "PULSE")
103     sink = new CAESinkPULSE();
104   #endif
105   #if defined(HAS_ALSA)
106   else if (driver == "ALSA")
107     sink = new CAESinkALSA();
108   #endif
109   else if (driver == "OSS")
110     sink = new CAESinkOSS();
111 #endif
112
113   if (!sink)
114     return NULL;
115
116   if (sink->Initialize(format, device))
117   {
118     return sink;
119   }
120   sink->Deinitialize();
121   delete sink;
122   return NULL;
123 }
124
125 IAESink *CAESinkFactory::Create(std::string &device, AEAudioFormat &desiredFormat, bool rawPassthrough)
126 {
127   // extract the driver from the device string if it exists
128   std::string driver;
129   ParseDevice(device, driver);
130
131   AEAudioFormat  tmpFormat = desiredFormat;
132   IAESink       *sink;
133   std::string    tmpDevice = device;
134
135   sink = TrySink(driver, tmpDevice, tmpFormat);
136   if (sink)
137   {
138     desiredFormat = tmpFormat;
139     return sink;
140   }
141
142   return NULL;
143 }
144
145 void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
146 {
147   AESinkInfo info;
148 #if defined(TARGET_WINDOWS)
149
150   info.m_deviceInfoList.clear();
151   info.m_sinkName = "DirectSound";
152   CAESinkDirectSound::EnumerateDevicesEx(info.m_deviceInfoList, force);
153   if(!info.m_deviceInfoList.empty())
154     list.push_back(info);
155
156   info.m_deviceInfoList.clear();
157   info.m_sinkName = "WASAPI";
158   CAESinkWASAPI::EnumerateDevicesEx(info.m_deviceInfoList, force);
159   if(!info.m_deviceInfoList.empty())
160     list.push_back(info);
161
162 #elif defined(TARGET_ANDROID)
163
164   info.m_deviceInfoList.clear();
165   info.m_sinkName = "AUDIOTRACK";
166   CAESinkAUDIOTRACK::EnumerateDevicesEx(info.m_deviceInfoList, force);
167   if(!info.m_deviceInfoList.empty())
168     list.push_back(info);
169
170 #elif defined(TARGET_RASPBERRY_PI)
171
172   info.m_deviceInfoList.clear();
173   info.m_sinkName = "PI";
174   CAESinkPi::EnumerateDevicesEx(info.m_deviceInfoList, force);
175   if(!info.m_deviceInfoList.empty())
176     list.push_back(info);
177
178 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
179   // check if user wants us to do something specific
180   if (getenv("AE_SINK"))
181   {
182     std::string envSink = (std::string)getenv("AE_SINK");
183     std::transform(envSink.begin(), envSink.end(), envSink.begin(), ::toupper);
184     info.m_deviceInfoList.clear();
185     #if defined(HAS_PULSEAUDIO)
186     if (envSink == "PULSE")
187       CAESinkPULSE::EnumerateDevicesEx(info.m_deviceInfoList, force);
188     #endif
189     #if defined(HAS_ALSA)
190     if (envSink == "ALSA")
191       CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force);
192     #endif
193     if (envSink == "OSS")
194       CAESinkOSS::EnumerateDevicesEx(info.m_deviceInfoList, force);
195
196     if(!info.m_deviceInfoList.empty())
197     {
198       info.m_sinkName = envSink;
199       list.push_back(info);
200       return;
201     }
202     else
203       CLog::Log(LOGNOTICE, "User specified Sink %s could not be enumerated", envSink.c_str());
204   }
205
206   #if defined(HAS_PULSEAUDIO)
207   info.m_deviceInfoList.clear();
208   info.m_sinkName = "PULSE";
209   CAESinkPULSE::EnumerateDevicesEx(info.m_deviceInfoList, force);
210   if(!info.m_deviceInfoList.empty())
211   {
212     list.push_back(info);
213     return;
214   }
215   #endif
216
217   #if defined(HAS_ALSA)
218   info.m_deviceInfoList.clear();
219   info.m_sinkName = "ALSA";
220   CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force);
221   if(!info.m_deviceInfoList.empty())
222     list.push_back(info);
223     return;
224   #endif
225
226   info.m_deviceInfoList.clear();
227   info.m_sinkName = "OSS";
228   CAESinkOSS::EnumerateDevicesEx(info.m_deviceInfoList, force);
229   if(!info.m_deviceInfoList.empty())
230     list.push_back(info);
231
232 #endif
233
234 }