audiodevicepulse.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. #include "audiodevicepulse.h"
  2. #include <string.h>
  3. #include <iostream>
  4. using namespace std;
  5. AudioDevicePulse::AudioDevicePulse()
  6. {
  7. m_initialized = false;
  8. m_paStateChanged = false;
  9. memset(m_paServerVersion, 0, 32);
  10. m_sample_rate_hz = 44100;
  11. }
  12. AudioDevicePulse::~AudioDevicePulse()
  13. {
  14. }
  15. InitStatus AudioDevicePulse::Init()
  16. {
  17. if (m_initialized) {
  18. return InitStatus::OK;
  19. }
  20. // Initialize PulseAudio
  21. if (InitPulseAudio() < 0) {
  22. cout<<"failed to initialize PulseAudio"<<endl;
  23. if (TerminatePulseAudio() < 0) {
  24. cout<<"failed to terminate PulseAudio"<<endl;
  25. }
  26. return InitStatus::OTHER_ERROR;
  27. }
  28. //// RECORDING
  29. //_ptrThreadRec.reset(new rtc::PlatformThread(
  30. // RecThreadFunc, this, "webrtc_audio_module_rec_thread"));
  31. //_ptrThreadRec->Start();
  32. //_ptrThreadRec->SetPriority(rtc::kRealtimePriority);
  33. //// PLAYOUT
  34. //_ptrThreadPlay.reset(new rtc::PlatformThread(
  35. // PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
  36. //_ptrThreadPlay->Start();
  37. //_ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
  38. m_initialized = true;
  39. return InitStatus::OK;
  40. }
  41. int32_t AudioDevicePulse::Terminate()
  42. {
  43. if (!m_initialized) {
  44. return 0;
  45. }
  46. //// RECORDING
  47. //if (_ptrThreadRec) {
  48. // rtc::PlatformThread* tmpThread = _ptrThreadRec.release();
  49. // _timeEventRec.Set();
  50. // tmpThread->Stop();
  51. // delete tmpThread;
  52. //}
  53. //// PLAYOUT
  54. //if (_ptrThreadPlay) {
  55. // rtc::PlatformThread* tmpThread = _ptrThreadPlay.release();
  56. // _timeEventPlay.Set();
  57. // tmpThread->Stop();
  58. // delete tmpThread;
  59. //}
  60. // Terminate PulseAudio
  61. if (TerminatePulseAudio() < 0) {
  62. cout << "failed to terminate PulseAudio"<<endl;
  63. return -1;
  64. }
  65. m_initialized = false;
  66. return 0;
  67. }
  68. bool AudioDevicePulse::Initialized() const {
  69. return (m_initialized);
  70. }
  71. int32_t AudioDevicePulse::InitPulseAudio()
  72. {
  73. int retVal = 0;
  74. // Create a mainloop API and connection to the default server
  75. // the mainloop is the internal asynchronous API event loop
  76. if (m_paMainloop) {
  77. printf("PA mainloop has already existed\n");
  78. return -1;
  79. }
  80. m_paMainloop = pa_threaded_mainloop_new();
  81. if (!m_paMainloop) {
  82. cout << "could not create main loop" << endl;;
  83. return -1;
  84. }
  85. // Start the threaded main loop
  86. retVal = pa_threaded_mainloop_start(m_paMainloop);
  87. if (retVal != PA_OK) {
  88. cout<<"failed to start main loop, error=" << retVal;
  89. return -1;
  90. }
  91. cout<< "main loop running!"<<endl;
  92. PaLock();
  93. m_paMainloopApi = pa_threaded_mainloop_get_api(m_paMainloop);
  94. if (!m_paMainloopApi) {
  95. cout<< "could not create main loop API"<<endl;
  96. PaUnLock();
  97. return -1;
  98. }
  99. // Create a new PulseAudio context
  100. if (m_paContext) {
  101. cout << "PA context has already existed";
  102. PaUnLock();
  103. return -1;
  104. }
  105. m_paContext = pa_context_new(m_paMainloopApi, "RVC VoiceEngine");
  106. if (!m_paContext) {
  107. cout << "could not create context"<<endl;
  108. PaUnLock();
  109. return -1;
  110. }
  111. // Set state callback function
  112. pa_context_set_state_callback(m_paContext, PaContextStateCallback, this);
  113. // Connect the context to a server (default)
  114. m_paStateChanged = false;
  115. retVal = pa_context_connect(m_paContext, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
  116. if (retVal != PA_OK) {
  117. cout << "failed to connect context, error=" << retVal<<endl;
  118. PaUnLock();
  119. return -1;
  120. }
  121. // Wait for state change
  122. while (!m_paStateChanged) {
  123. pa_threaded_mainloop_wait(m_paMainloop);
  124. }
  125. // Now check to see what final state we reached.
  126. pa_context_state_t state = pa_context_get_state(m_paContext);
  127. if (state != PA_CONTEXT_READY) {
  128. if (state == PA_CONTEXT_FAILED) {
  129. cout << "failed to connect to PulseAudio sound server";
  130. }
  131. else if (state == PA_CONTEXT_TERMINATED) {
  132. cout << "PulseAudio connection terminated early";
  133. }
  134. else {
  135. // Shouldn't happen, because we only signal on one of those three
  136. // states
  137. cout << "unknown problem connecting to PulseAudio";
  138. }
  139. PaUnLock();
  140. return -1;
  141. }
  142. PaUnLock();
  143. // Give the objects to the mixer manager
  144. //_mixerManager.SetPulseAudioObjects(_paMainloop, _paContext);
  145. // Check the version
  146. if (CheckPulseAudioVersion() < 0) {
  147. cout << "PulseAudio version " << m_paServerVersion << " not supported";
  148. return -1;
  149. }
  150. // Initialize sampling frequency
  151. if (InitSamplingFrequency() < 0 || m_sample_rate_hz == 0) {
  152. cout << "failed to initialize sampling frequency, set to "<< m_sample_rate_hz << " Hz";
  153. return -1;
  154. }
  155. return 0;
  156. }
  157. int32_t AudioDevicePulse::TerminatePulseAudio() {
  158. // Do nothing if the instance doesn't exist
  159. // likely PaSymbolTable.Load() fails
  160. if (!m_paMainloop) {
  161. return 0;
  162. }
  163. PaLock();
  164. // Disconnect the context
  165. if (m_paContext) {
  166. (pa_context_disconnect)(m_paContext);
  167. }
  168. // Unreference the context
  169. if (m_paContext) {
  170. (pa_context_unref)(m_paContext);
  171. }
  172. PaUnLock();
  173. m_paContext = NULL;
  174. // Stop the threaded main loop
  175. if (m_paMainloop) {
  176. (pa_threaded_mainloop_stop)(m_paMainloop);
  177. }
  178. // Free the mainloop
  179. if (m_paMainloop) {
  180. (pa_threaded_mainloop_free)(m_paMainloop);
  181. }
  182. m_paMainloop = NULL;
  183. cout << "PulseAudio terminated"<<endl;
  184. return 0;
  185. }
  186. void AudioDevicePulse::PaLock()
  187. {
  188. pa_threaded_mainloop_lock(m_paMainloop);
  189. }
  190. void AudioDevicePulse::PaUnLock()
  191. {
  192. pa_threaded_mainloop_unlock(m_paMainloop);
  193. }
  194. int32_t AudioDevicePulse::CheckPulseAudioVersion()
  195. {
  196. PaLock();
  197. pa_operation* paOperation = NULL;
  198. // get the server info and update deviceName
  199. paOperation = pa_context_get_server_info(m_paContext, PaServerInfoCallback, this);
  200. WaitForOperationCompletion(paOperation);
  201. PaUnLock();
  202. cout << "checking PulseAudio version: " << m_paServerVersion<<endl;
  203. return 0;
  204. }
  205. void AudioDevicePulse::WaitForOperationCompletion(pa_operation* paOperation) const
  206. {
  207. if (!paOperation) {
  208. cout << "paOperation NULL in WaitForOperationCompletion"<<endl;
  209. return;
  210. }
  211. while (pa_operation_get_state(paOperation) == PA_OPERATION_RUNNING) {
  212. pa_threaded_mainloop_wait(m_paMainloop);
  213. }
  214. pa_operation_unref(paOperation);
  215. }
  216. int32_t AudioDevicePulse::InitSamplingFrequency()
  217. {
  218. PaLock();
  219. pa_operation* paOperation = NULL;
  220. // Get the server info and update sample_rate_hz_
  221. paOperation = pa_context_get_server_info(m_paContext, PaServerInfoCallback, this);
  222. WaitForOperationCompletion(paOperation);
  223. PaUnLock();
  224. return 0;
  225. }
  226. void AudioDevicePulse::PaServerInfoCallback(pa_context* c,const pa_server_info* i,void* pThis)
  227. {
  228. static_cast<AudioDevicePulse*>(pThis)->PaServerInfoCallbackHandler(i);
  229. }
  230. void AudioDevicePulse::PaContextStateCallback(pa_context* c, void* pThis)
  231. {
  232. static_cast<AudioDevicePulse*>(pThis)->PaContextStateCallbackHandler(c);
  233. }
  234. void AudioDevicePulse::PaServerInfoCallbackHandler(const pa_server_info* i)
  235. {
  236. // Use PA native sampling rate
  237. m_sample_rate_hz = i->sample_spec.rate;
  238. // Copy the PA server version
  239. strncpy(m_paServerVersion, i->server_version, 31);
  240. m_paServerVersion[31] = '\0';
  241. //if (_recDisplayDeviceName) {
  242. // // Copy the source name
  243. // strncpy(_recDisplayDeviceName, i->default_source_name,
  244. // kAdmMaxDeviceNameSize);
  245. // _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
  246. //}
  247. //if (_playDisplayDeviceName) {
  248. // // Copy the sink name
  249. // strncpy(_playDisplayDeviceName, i->default_sink_name,
  250. // kAdmMaxDeviceNameSize);
  251. // _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
  252. //}
  253. pa_threaded_mainloop_signal(m_paMainloop, 0);
  254. }
  255. void AudioDevicePulse::PaContextStateCallbackHandler(pa_context* c)
  256. {
  257. cout << "context state cb" <<endl;
  258. pa_context_state_t state = pa_context_get_state(c);
  259. switch (state) {
  260. case PA_CONTEXT_UNCONNECTED:
  261. cout << "unconnected"<<endl;
  262. break;
  263. case PA_CONTEXT_CONNECTING:
  264. case PA_CONTEXT_AUTHORIZING:
  265. case PA_CONTEXT_SETTING_NAME:
  266. cout << "no state" << endl;
  267. break;
  268. case PA_CONTEXT_FAILED:
  269. case PA_CONTEXT_TERMINATED:
  270. cout << "failed" << endl;
  271. m_paStateChanged = true;
  272. pa_threaded_mainloop_signal(m_paMainloop, 0);
  273. break;
  274. case PA_CONTEXT_READY:
  275. cout << "ready" << endl;
  276. m_paStateChanged = true;
  277. (pa_threaded_mainloop_signal)(m_paMainloop, 0);
  278. break;
  279. }
  280. }