forked from margro/xbmc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
1,372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
/* | ||
* Copyright (C) 2010-2012 Team XBMC | ||
* http://xbmc.org | ||
* | ||
* This Program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
* | ||
* This Program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with XBMC; see the file COPYING. If not, write to | ||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
* http://www.gnu.org/copyleft/gpl.html | ||
* | ||
*/ | ||
|
||
#include "system.h" | ||
#ifdef HAS_PULSEAUDIO | ||
|
||
#include "PulseAE.h" | ||
#include "PulseAEStream.h" | ||
#include "PulseAESound.h" | ||
#include "threads/SingleLock.h" | ||
#include "utils/log.h" | ||
#include "settings/Settings.h" | ||
#include <pulse/pulseaudio.h> | ||
|
||
/* Static helpers */ | ||
static const char *ContextStateToString(pa_context_state s) | ||
{ | ||
switch (s) | ||
{ | ||
case PA_CONTEXT_UNCONNECTED: | ||
return "unconnected"; | ||
case PA_CONTEXT_CONNECTING: | ||
return "connecting"; | ||
case PA_CONTEXT_AUTHORIZING: | ||
return "authorizing"; | ||
case PA_CONTEXT_SETTING_NAME: | ||
return "setting name"; | ||
case PA_CONTEXT_READY: | ||
return "ready"; | ||
case PA_CONTEXT_FAILED: | ||
return "failed"; | ||
case PA_CONTEXT_TERMINATED: | ||
return "terminated"; | ||
default: | ||
return "none"; | ||
} | ||
} | ||
|
||
#if 0 | ||
static const char *StreamStateToString(pa_stream_state s) | ||
{ | ||
switch(s) | ||
{ | ||
case PA_STREAM_UNCONNECTED: | ||
return "unconnected"; | ||
case PA_STREAM_CREATING: | ||
return "creating"; | ||
case PA_STREAM_READY: | ||
return "ready"; | ||
case PA_STREAM_FAILED: | ||
return "failed"; | ||
case PA_STREAM_TERMINATED: | ||
return "terminated"; | ||
default: | ||
return "none"; | ||
} | ||
} | ||
#endif | ||
|
||
CPulseAE::CPulseAE() | ||
{ | ||
m_Context = NULL; | ||
m_MainLoop = NULL; | ||
} | ||
|
||
CPulseAE::~CPulseAE() | ||
{ | ||
if (m_MainLoop) | ||
pa_threaded_mainloop_stop(m_MainLoop); | ||
|
||
if (m_Context) | ||
{ | ||
pa_context_disconnect(m_Context); | ||
pa_context_unref(m_Context); | ||
m_Context = NULL; | ||
} | ||
} | ||
|
||
bool CPulseAE::Initialize() | ||
{ | ||
m_Volume = g_settings.m_fVolumeLevel; | ||
|
||
if ((m_MainLoop = pa_threaded_mainloop_new()) == NULL) | ||
{ | ||
CLog::Log(LOGERROR, "PulseAudio: Failed to allocate main loop"); | ||
return false; | ||
} | ||
|
||
if ((m_Context = pa_context_new(pa_threaded_mainloop_get_api(m_MainLoop), "XBMC")) == NULL) | ||
{ | ||
CLog::Log(LOGERROR, "PulseAudio: Failed to allocate context"); | ||
return false; | ||
} | ||
|
||
pa_context_set_state_callback(m_Context, ContextStateCallback, m_MainLoop); | ||
|
||
if (pa_context_connect(m_Context, NULL, (pa_context_flags_t)0, NULL) < 0) | ||
{ | ||
CLog::Log(LOGERROR, "PulseAudio: Failed to connect context"); | ||
return false; | ||
} | ||
|
||
pa_threaded_mainloop_lock(m_MainLoop); | ||
if (pa_threaded_mainloop_start(m_MainLoop) < 0) | ||
{ | ||
CLog::Log(LOGERROR, "PulseAudio: Failed to start MainLoop"); | ||
pa_threaded_mainloop_unlock(m_MainLoop); | ||
return false; | ||
} | ||
|
||
/* Wait until the context is ready */ | ||
do | ||
{ | ||
pa_threaded_mainloop_wait(m_MainLoop); | ||
CLog::Log(LOGDEBUG, "PulseAudio: Context %s", ContextStateToString(pa_context_get_state(m_Context))); | ||
} | ||
while (pa_context_get_state(m_Context) != PA_CONTEXT_READY && pa_context_get_state(m_Context) != PA_CONTEXT_FAILED); | ||
|
||
if (pa_context_get_state(m_Context) == PA_CONTEXT_FAILED) | ||
{ | ||
CLog::Log(LOGERROR, "PulseAudio: Waited for the Context but it failed"); | ||
pa_threaded_mainloop_unlock(m_MainLoop); | ||
return false; | ||
} | ||
|
||
pa_threaded_mainloop_unlock(m_MainLoop); | ||
return true; | ||
} | ||
|
||
void CPulseAE::OnSettingsChange(std::string setting) | ||
{ | ||
} | ||
|
||
float CPulseAE::GetVolume() | ||
{ | ||
return m_Volume; | ||
} | ||
|
||
void CPulseAE::SetVolume(float volume) | ||
{ | ||
CSingleLock lock(m_lock); | ||
m_Volume = volume; | ||
std::list<CPulseAEStream*>::iterator itt; | ||
for (itt = m_streams.begin(); itt != m_streams.end(); ++itt) | ||
(*itt)->UpdateVolume(volume); | ||
} | ||
|
||
IAEStream *CPulseAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, CAEChannelInfo channelLayout, unsigned int options) | ||
{ | ||
CPulseAEStream *st = new CPulseAEStream(m_Context, m_MainLoop, dataFormat, sampleRate, channelLayout, options); | ||
|
||
CSingleLock lock(m_lock); | ||
m_streams.push_back(st); | ||
return st; | ||
} | ||
|
||
void CPulseAE::RemoveStream(IAEStream *stream) | ||
{ | ||
std::list<CPulseAEStream*>::iterator itt; | ||
|
||
m_streams.remove((CPulseAEStream *)stream); | ||
|
||
for (itt = m_streams.begin(); itt != m_streams.end(); ++itt) | ||
{ | ||
if (*itt == stream) | ||
{ | ||
m_streams.erase(itt); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
IAEStream *CPulseAE::FreeStream(IAEStream *stream) | ||
{ | ||
RemoveStream(stream); | ||
|
||
CPulseAEStream *istream = (CPulseAEStream *)stream; | ||
|
||
delete istream; | ||
|
||
return NULL; | ||
} | ||
|
||
IAESound *CPulseAE::MakeSound(const std::string& file) | ||
{ | ||
CSingleLock lock(m_lock); | ||
|
||
CPulseAESound *sound = new CPulseAESound(file, m_Context, m_MainLoop); | ||
if (!sound->Initialize()) | ||
{ | ||
delete sound; | ||
return NULL; | ||
} | ||
|
||
m_sounds.push_back(sound); | ||
return sound; | ||
} | ||
|
||
void CPulseAE::FreeSound(IAESound *sound) | ||
{ | ||
if (!sound) | ||
return; | ||
|
||
sound->Stop(); | ||
CSingleLock lock(m_lock); | ||
for (std::list<CPulseAESound*>::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt) | ||
if (*itt == sound) | ||
{ | ||
m_sounds.erase(itt); | ||
break; | ||
} | ||
|
||
delete (CPulseAESound*)sound; | ||
} | ||
|
||
void CPulseAE::GarbageCollect() | ||
{ | ||
CSingleLock lock(m_lock); | ||
std::list<CPulseAEStream*>::iterator itt; | ||
for (itt = m_streams.begin(); itt != m_streams.end();) | ||
{ | ||
if ((*itt)->IsDestroyed()) | ||
{ | ||
delete (*itt); | ||
itt = m_streams.erase(itt); | ||
continue; | ||
} | ||
++itt; | ||
} | ||
} | ||
|
||
void CPulseAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) | ||
{ | ||
} | ||
|
||
void CPulseAE::ContextStateCallback(pa_context *c, void *userdata) | ||
{ | ||
pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata; | ||
switch (pa_context_get_state(c)) | ||
{ | ||
case PA_CONTEXT_READY: | ||
case PA_CONTEXT_TERMINATED: | ||
case PA_CONTEXT_UNCONNECTED: | ||
case PA_CONTEXT_CONNECTING: | ||
case PA_CONTEXT_AUTHORIZING: | ||
case PA_CONTEXT_SETTING_NAME: | ||
case PA_CONTEXT_FAILED: | ||
pa_threaded_mainloop_signal(m, 0); | ||
break; | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#pragma once | ||
/* | ||
* Copyright (C) 2010-2012 Team XBMC | ||
* http://xbmc.org | ||
* | ||
* This Program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
* | ||
* This Program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with XBMC; see the file COPYING. If not, write to | ||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
* http://www.gnu.org/copyleft/gpl.html | ||
* | ||
*/ | ||
|
||
#include "system.h" | ||
#ifdef HAS_PULSEAUDIO | ||
|
||
#include "Interfaces/AE.h" | ||
#include "PulseAEStream.h" | ||
#include "PulseAESound.h" | ||
#include "threads/CriticalSection.h" | ||
#include <list> | ||
|
||
struct pa_context; | ||
struct pa_threaded_mainloop; | ||
struct pa_stream; | ||
|
||
class CPulseAEStream; | ||
class CPulseAESound; | ||
class CPulseAE : public IAE | ||
{ | ||
protected: | ||
friend class CAEFactory; | ||
CPulseAE(); | ||
virtual ~CPulseAE(); | ||
|
||
public: | ||
virtual bool Initialize (); | ||
virtual void OnSettingsChange(std::string setting); | ||
|
||
virtual float GetVolume(); | ||
virtual void SetVolume(float volume); | ||
|
||
/* returns a new stream for data in the specified format */ | ||
virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, CAEChannelInfo channelLayout, unsigned int options = 0); | ||
virtual IAEStream *FreeStream(IAEStream *stream); | ||
void RemoveStream(IAEStream *stream); | ||
|
||
/* returns a new sound object */ | ||
virtual IAESound *MakeSound(const std::string& file); | ||
virtual void FreeSound(IAESound *sound); | ||
|
||
/* free's sounds that have expired */ | ||
virtual void GarbageCollect(); | ||
|
||
virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); | ||
private: | ||
CCriticalSection m_lock; | ||
std::list<CPulseAEStream*> m_streams; | ||
std::list<CPulseAESound* > m_sounds; | ||
|
||
static void ContextStateCallback(pa_context *c, void *userdata); | ||
|
||
pa_context *m_Context; | ||
pa_threaded_mainloop *m_MainLoop; | ||
float m_Volume; | ||
}; | ||
|
||
#endif |
Oops, something went wrong.