123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- #include "audiodevicepulse.h"
- #include <string.h>
- #include <iostream>
- using namespace std;
- AudioDevicePulse::AudioDevicePulse()
- {
- m_initialized = false;
- m_paStateChanged = false;
- memset(m_paServerVersion, 0, 32);
- m_sample_rate_hz = 44100;
- }
- AudioDevicePulse::~AudioDevicePulse()
- {
- }
- InitStatus AudioDevicePulse::Init()
- {
- if (m_initialized) {
- return InitStatus::OK;
- }
- // Initialize PulseAudio
- if (InitPulseAudio() < 0) {
- cout<<"failed to initialize PulseAudio"<<endl;
- if (TerminatePulseAudio() < 0) {
- cout<<"failed to terminate PulseAudio"<<endl;
- }
- return InitStatus::OTHER_ERROR;
- }
- //// RECORDING
- //_ptrThreadRec.reset(new rtc::PlatformThread(
- // RecThreadFunc, this, "webrtc_audio_module_rec_thread"));
- //_ptrThreadRec->Start();
- //_ptrThreadRec->SetPriority(rtc::kRealtimePriority);
- //// PLAYOUT
- //_ptrThreadPlay.reset(new rtc::PlatformThread(
- // PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
- //_ptrThreadPlay->Start();
- //_ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
- m_initialized = true;
- return InitStatus::OK;
- }
- int32_t AudioDevicePulse::Terminate()
- {
- if (!m_initialized) {
- return 0;
- }
- //// RECORDING
- //if (_ptrThreadRec) {
- // rtc::PlatformThread* tmpThread = _ptrThreadRec.release();
- // _timeEventRec.Set();
- // tmpThread->Stop();
- // delete tmpThread;
- //}
- //// PLAYOUT
- //if (_ptrThreadPlay) {
- // rtc::PlatformThread* tmpThread = _ptrThreadPlay.release();
- // _timeEventPlay.Set();
- // tmpThread->Stop();
- // delete tmpThread;
- //}
- // Terminate PulseAudio
- if (TerminatePulseAudio() < 0) {
- cout << "failed to terminate PulseAudio"<<endl;
- return -1;
- }
- m_initialized = false;
- return 0;
- }
- bool AudioDevicePulse::Initialized() const {
- return (m_initialized);
- }
- int32_t AudioDevicePulse::InitPulseAudio()
- {
- int retVal = 0;
- // Create a mainloop API and connection to the default server
- // the mainloop is the internal asynchronous API event loop
- if (m_paMainloop) {
- printf("PA mainloop has already existed\n");
- return -1;
- }
- m_paMainloop = pa_threaded_mainloop_new();
- if (!m_paMainloop) {
- cout << "could not create main loop" << endl;;
- return -1;
- }
- // Start the threaded main loop
- retVal = pa_threaded_mainloop_start(m_paMainloop);
- if (retVal != PA_OK) {
- cout<<"failed to start main loop, error=" << retVal;
- return -1;
- }
- cout<< "main loop running!"<<endl;
- PaLock();
- m_paMainloopApi = pa_threaded_mainloop_get_api(m_paMainloop);
- if (!m_paMainloopApi) {
- cout<< "could not create main loop API"<<endl;
- PaUnLock();
- return -1;
- }
- // Create a new PulseAudio context
- if (m_paContext) {
- cout << "PA context has already existed";
- PaUnLock();
- return -1;
- }
- m_paContext = pa_context_new(m_paMainloopApi, "RVC VoiceEngine");
- if (!m_paContext) {
- cout << "could not create context"<<endl;
- PaUnLock();
- return -1;
- }
- // Set state callback function
- pa_context_set_state_callback(m_paContext, PaContextStateCallback, this);
- // Connect the context to a server (default)
- m_paStateChanged = false;
- retVal = pa_context_connect(m_paContext, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
- if (retVal != PA_OK) {
- cout << "failed to connect context, error=" << retVal<<endl;
- PaUnLock();
- return -1;
- }
- // Wait for state change
- while (!m_paStateChanged) {
- pa_threaded_mainloop_wait(m_paMainloop);
- }
- // Now check to see what final state we reached.
- pa_context_state_t state = pa_context_get_state(m_paContext);
- if (state != PA_CONTEXT_READY) {
- if (state == PA_CONTEXT_FAILED) {
- cout << "failed to connect to PulseAudio sound server";
- }
- else if (state == PA_CONTEXT_TERMINATED) {
- cout << "PulseAudio connection terminated early";
- }
- else {
- // Shouldn't happen, because we only signal on one of those three
- // states
- cout << "unknown problem connecting to PulseAudio";
- }
- PaUnLock();
- return -1;
- }
- PaUnLock();
- // Give the objects to the mixer manager
- //_mixerManager.SetPulseAudioObjects(_paMainloop, _paContext);
- // Check the version
- if (CheckPulseAudioVersion() < 0) {
- cout << "PulseAudio version " << m_paServerVersion << " not supported";
- return -1;
- }
- // Initialize sampling frequency
- if (InitSamplingFrequency() < 0 || m_sample_rate_hz == 0) {
- cout << "failed to initialize sampling frequency, set to "<< m_sample_rate_hz << " Hz";
- return -1;
- }
- return 0;
- }
- int32_t AudioDevicePulse::TerminatePulseAudio() {
- // Do nothing if the instance doesn't exist
- // likely PaSymbolTable.Load() fails
- if (!m_paMainloop) {
- return 0;
- }
- PaLock();
- // Disconnect the context
- if (m_paContext) {
- (pa_context_disconnect)(m_paContext);
- }
- // Unreference the context
- if (m_paContext) {
- (pa_context_unref)(m_paContext);
- }
- PaUnLock();
- m_paContext = NULL;
- // Stop the threaded main loop
- if (m_paMainloop) {
- (pa_threaded_mainloop_stop)(m_paMainloop);
- }
- // Free the mainloop
- if (m_paMainloop) {
- (pa_threaded_mainloop_free)(m_paMainloop);
- }
- m_paMainloop = NULL;
- cout << "PulseAudio terminated"<<endl;
- return 0;
- }
- void AudioDevicePulse::PaLock()
- {
- pa_threaded_mainloop_lock(m_paMainloop);
- }
- void AudioDevicePulse::PaUnLock()
- {
- pa_threaded_mainloop_unlock(m_paMainloop);
- }
- int32_t AudioDevicePulse::CheckPulseAudioVersion()
- {
- PaLock();
- pa_operation* paOperation = NULL;
- // get the server info and update deviceName
- paOperation = pa_context_get_server_info(m_paContext, PaServerInfoCallback, this);
- WaitForOperationCompletion(paOperation);
- PaUnLock();
- cout << "checking PulseAudio version: " << m_paServerVersion<<endl;
- return 0;
- }
- void AudioDevicePulse::WaitForOperationCompletion(pa_operation* paOperation) const
- {
- if (!paOperation) {
- cout << "paOperation NULL in WaitForOperationCompletion"<<endl;
- return;
- }
- while (pa_operation_get_state(paOperation) == PA_OPERATION_RUNNING) {
- pa_threaded_mainloop_wait(m_paMainloop);
- }
- pa_operation_unref(paOperation);
- }
- int32_t AudioDevicePulse::InitSamplingFrequency()
- {
- PaLock();
- pa_operation* paOperation = NULL;
- // Get the server info and update sample_rate_hz_
- paOperation = pa_context_get_server_info(m_paContext, PaServerInfoCallback, this);
- WaitForOperationCompletion(paOperation);
- PaUnLock();
- return 0;
- }
- void AudioDevicePulse::PaServerInfoCallback(pa_context* c,const pa_server_info* i,void* pThis)
- {
- static_cast<AudioDevicePulse*>(pThis)->PaServerInfoCallbackHandler(i);
- }
- void AudioDevicePulse::PaContextStateCallback(pa_context* c, void* pThis)
- {
- static_cast<AudioDevicePulse*>(pThis)->PaContextStateCallbackHandler(c);
- }
- void AudioDevicePulse::PaServerInfoCallbackHandler(const pa_server_info* i)
- {
- // Use PA native sampling rate
- m_sample_rate_hz = i->sample_spec.rate;
- // Copy the PA server version
- strncpy(m_paServerVersion, i->server_version, 31);
- m_paServerVersion[31] = '\0';
- //if (_recDisplayDeviceName) {
- // // Copy the source name
- // strncpy(_recDisplayDeviceName, i->default_source_name,
- // kAdmMaxDeviceNameSize);
- // _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
- //}
- //if (_playDisplayDeviceName) {
- // // Copy the sink name
- // strncpy(_playDisplayDeviceName, i->default_sink_name,
- // kAdmMaxDeviceNameSize);
- // _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
- //}
- pa_threaded_mainloop_signal(m_paMainloop, 0);
- }
- void AudioDevicePulse::PaContextStateCallbackHandler(pa_context* c)
- {
- cout << "context state cb" <<endl;
- pa_context_state_t state = pa_context_get_state(c);
- switch (state) {
- case PA_CONTEXT_UNCONNECTED:
- cout << "unconnected"<<endl;
- break;
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- cout << "no state" << endl;
- break;
- case PA_CONTEXT_FAILED:
- case PA_CONTEXT_TERMINATED:
- cout << "failed" << endl;
- m_paStateChanged = true;
- pa_threaded_mainloop_signal(m_paMainloop, 0);
- break;
- case PA_CONTEXT_READY:
- cout << "ready" << endl;
- m_paStateChanged = true;
- (pa_threaded_mainloop_signal)(m_paMainloop, 0);
- break;
- }
- }
|