Guest User

Untitled

a guest
Nov 24th, 2017
329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.81 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2011 Michael 'Mickey' Lauer <mlauer@vanille-media.de>
  3. * Copyright (C) 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9.  
  10. * This library 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 GNU
  13. * Lesser General Public License for more details.
  14.  
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. *
  19. */
  20.  
  21. //TODO: handle that: CMTSPEECH: UL frame send failed with -1 (16: Device or resource busy)
  22.  
  23.  
  24. /**
  25. * @class CmtHandler
  26. *
  27. * Handles Audio via libcmtspeechdata
  28. **/
  29. public class CmtHandler : FsoFramework.AbstractObject
  30. {
  31. private CmtSpeech.Connection connection;
  32. private IOChannel channel;
  33. private int data_fd;
  34. private FsoAudio.PcmDevice pcmout;
  35. private FsoAudio.PcmDevice pcmin;
  36.  
  37. private bool status;
  38.  
  39. //TODO: add config for that
  40. private const bool file_interface = false;
  41. private const bool loop_interface = false;
  42. private const bool alsa_interface = true;
  43.  
  44. private const string voice_file = "/home/root/voice/voice_data.raw";
  45. private unowned Thread<void *> recordThread = null;
  46. private bool runRecordThread = false;
  47. private uint8 alsaSrcBuf[320];
  48. //
  49. // Constructor
  50. //
  51. public CmtHandler()
  52. {
  53. status = false;
  54.  
  55. assert( logger.debug( "Initializing cmtspeech" ) );
  56. CmtSpeech.init();
  57.  
  58. assert( logger.debug( "Setting up traces" ) );
  59. CmtSpeech.trace_toggle( CmtSpeech.TraceType.STATE_CHANGE, true );
  60. CmtSpeech.trace_toggle( CmtSpeech.TraceType.IO, true );
  61. CmtSpeech.trace_toggle( CmtSpeech.TraceType.DEBUG, true );
  62.  
  63. assert( logger.debug( "Instanciating connection" ) );
  64. connection = new CmtSpeech.Connection();
  65. if ( connection == null )
  66. {
  67. logger.error( "Can't instanciate connection" );
  68. return;
  69. }
  70.  
  71. var fd = connection.descriptor();
  72.  
  73. if ( fd == -1 )
  74. {
  75. logger.error( "Cmtspeech file descriptor invalid" );
  76. }
  77.  
  78. assert( logger.debug( "Hooking up fd with main loop" ) );
  79. channel = new IOChannel.unix_new( fd );
  80. channel.add_watch( IOCondition.IN | IOCondition.HUP, onInputFromChannel );
  81.  
  82. logger.info( "Created" );
  83. }
  84.  
  85. //
  86. // Private API
  87. //
  88.  
  89. private void * recordThreadFunc(){
  90. while (true)
  91. {
  92. while (runRecordThread){
  93. lock(alsaSrcBuf){
  94. try{
  95. pcmin.read( alsaSrcBuf, 160 /* 160 S16_LE frames == 320 */ );
  96. }catch(FsoAudio.SoundError e){
  97. logger.error( @"Error: $(e.message)" );
  98. }
  99. }
  100. }
  101. }
  102. return null;
  103. }
  104.  
  105. private void handleAlsaSrc()
  106. {
  107. CmtSpeech.FrameBuffer ulbuf = null;
  108. var ok = connection.ul_buffer_acquire( out ulbuf );
  109. if (ok == 0)
  110. {
  111. assert( logger.debug( "protocol state is ACTIVE_DLUL, uploading as well..." ) );
  112. lock (alsaSrcBuf){
  113. Memory.copy((uint8[])ulbuf.payload, alsaSrcBuf, 160);
  114. }
  115. /* ulbuf.pcount / 2 */ /* S16_LE Frames */
  116. connection.ul_buffer_release( ulbuf );
  117. }
  118. }
  119.  
  120. private void handleAlsaSink()
  121. {
  122. CmtSpeech.FrameBuffer dlbuf = null;
  123. var ok = connection.dl_buffer_acquire( out dlbuf );
  124. if ( ok == 0 )
  125. {
  126. assert( logger.debug( "received DL packet w/ $(dlbuf.count) bytes" ) );
  127. try {
  128. pcmout.write( (uint8[])dlbuf.payload, dlbuf.pcount / 2 /* S16_LE frames */ );
  129. }catch (FsoAudio.SoundError e){
  130. logger.error( @"Error: $(e.message)" );
  131. }
  132. connection.dl_buffer_release( dlbuf );
  133. }
  134. }
  135.  
  136. private void alsaSinkSetup()
  137. {
  138. int channels = 1;
  139. int rate = 8000;
  140. Alsa2.PcmFormat format = Alsa2.PcmFormat.S16_LE;
  141. Alsa2.PcmAccess access = Alsa2.PcmAccess.RW_INTERLEAVED;
  142.  
  143. pcmout = new FsoAudio.PcmDevice();
  144. assert( logger.debug( @"Setup alsa sink for modem audio" ) );
  145. try
  146. {
  147. pcmout.open( "plug:dmix" );
  148. pcmout.setFormat( access, format, rate, channels );
  149. }
  150. catch ( Error e )
  151. {
  152. logger.error( @"Error: $(e.message)" );
  153. }
  154. }
  155.  
  156. private void alsaSrcSetup()
  157. {
  158. int channels = 1;
  159. int rate = 8000;
  160. Alsa2.PcmFormat format = Alsa2.PcmFormat.S16_LE;
  161. Alsa2.PcmAccess access = Alsa2.PcmAccess.RW_INTERLEAVED;
  162.  
  163. pcmin = new FsoAudio.PcmDevice();
  164. assert( logger.debug( @"Setup alsa source for modem audio" ) );
  165. try
  166. {
  167. pcmin.open( "plug:dsnoop", Alsa2.PcmStream.CAPTURE );
  168. pcmin.setFormat( access, format, rate, channels );
  169. }
  170. catch ( Error e )
  171. {
  172. logger.error( @"Error: $(e.message)" );
  173. }
  174.  
  175.  
  176. /* start the recording now,
  177. * so we push the buffer that are already recorded
  178. */
  179. if (!Thread.supported()) {
  180. stderr.printf("Cannot run without threads.\n");
  181. }else {
  182. if (recordThread == null){
  183. try {
  184. recordThread = Thread.create<void *>(recordThreadFunc, true);
  185. } catch (ThreadError e) {
  186. stdout.printf( @"Error: $(e.message)" );
  187. return;
  188. }
  189. }
  190. runRecordThread = true;
  191. }
  192.  
  193. }
  194.  
  195. private void alsaSinkCleanup()
  196. {
  197. pcmout.close();
  198. }
  199.  
  200. private void alsaSrcCleanup()
  201. {
  202. runRecordThread = false;
  203. recordThread.join();
  204. pcmin.close();
  205. }
  206.  
  207. private void handleDataEvent()
  208. {
  209. assert( logger.debug( @"handleDataEvent during protocol state $(connection.protocol_state())" ) );
  210.  
  211. if ( connection.protocol_state() == CmtSpeech.State.ACTIVE_DLUL )
  212. {
  213. handleAlsaSink();
  214. handleAlsaSrc();
  215. }
  216.  
  217. }
  218.  
  219. private void handleControlEvent()
  220. {
  221. assert( logger.debug( @"handleControlEvent during protocol state $(connection.protocol_state())" ) );
  222.  
  223. CmtSpeech.Event event = CmtSpeech.Event();
  224. CmtSpeech.Transition transition = 0;
  225.  
  226. connection.read_event( event );
  227.  
  228. assert( logger.debug( @"read event, type is $(event.msg_type)" ) );
  229. transition = connection.event_to_state_transition( event );
  230.  
  231. switch ( transition )
  232. {
  233. case CmtSpeech.Transition.INVALID:
  234. assert( logger.debug( "ERROR: invalid state transition") );
  235. break;
  236.  
  237. case CmtSpeech.Transition.1_CONNECTED:
  238. case CmtSpeech.Transition.2_DISCONNECTED:
  239. case CmtSpeech.Transition.3_DL_START:
  240. case CmtSpeech.Transition.4_DLUL_STOP:
  241. case CmtSpeech.Transition.5_PARAM_UPDATE:
  242. assert( logger.debug( @"State transition ok, new state is $transition" ) );
  243. break;
  244.  
  245. case CmtSpeech.Transition.6_TIMING_UPDATE:
  246. case CmtSpeech.Transition.7_TIMING_UPDATE:
  247. assert( logger.debug( "WARNING: modem UL timing update ignored" ) );
  248. break;
  249.  
  250. case CmtSpeech.Transition.10_RESET:
  251. case CmtSpeech.Transition.11_UL_STOP:
  252. case CmtSpeech.Transition.12_UL_START:
  253. assert( logger.debug( @"State transition ok, new state is $transition" ) );
  254. break;
  255.  
  256. default:
  257. assert_not_reached();
  258. }
  259. }
  260.  
  261. private bool onInputFromChannel( IOChannel source, IOCondition condition )
  262. {
  263. assert( logger.debug( "onInputFromChannel, condition = %d".printf( condition ) ) );
  264.  
  265. assert( condition == IOCondition.HUP || condition == IOCondition.IN );
  266.  
  267. if ( condition == IOCondition.HUP )
  268. {
  269. logger.warning( "HUP! Will no longer handle input from cmtspeechdata" );
  270. return false;
  271. }
  272.  
  273. CmtSpeech.EventType flags = 0;
  274. var ok = connection.check_pending( out flags );
  275. if ( ok < 0 )
  276. {
  277. assert( logger.debug( "Error while checking for pending events..." ) );
  278. }
  279. else if ( ok == 0 )
  280. {
  281. assert( logger.debug( "D'oh, cmt speech readable, but no events pending..." ) );
  282. }
  283. else
  284. {
  285. assert( logger.debug( "Connection reports pending events with flags 0x%0X".printf( flags ) ) );
  286.  
  287. if ( ( flags & CmtSpeech.EventType.DL_DATA ) == CmtSpeech.EventType.DL_DATA )
  288. {
  289. handleDataEvent();
  290. }
  291. else if ( ( flags & CmtSpeech.EventType.CONTROL ) == CmtSpeech.EventType.CONTROL )
  292. {
  293. handleControlEvent();
  294. }
  295. else
  296. {
  297. assert( logger.debug( "Event no DL_DATA nor CONTROL, ignoring" ) );
  298. }
  299. }
  300.  
  301. return true;
  302. }
  303.  
  304. //
  305. // Public API
  306. //
  307.  
  308. public override string repr()
  309. {
  310. CmtSpeech.State state = ( connection != null ) ? connection.protocol_state() : 0;
  311. return @"<$state>";
  312. }
  313.  
  314. public void setAudioStatus( bool enabled )
  315. {
  316. if ( enabled == status )
  317. {
  318. assert( logger.debug( @"Status already $status" ) );
  319. return;
  320. }
  321.  
  322. assert( logger.debug( @"Setting call status to $enabled" ) );
  323.  
  324. if ( enabled )
  325. {
  326. alsaSinkSetup();
  327. alsaSrcSetup();
  328. }
  329. else
  330. {
  331. alsaSinkCleanup();
  332. alsaSrcCleanup();
  333. }
  334.  
  335. connection.state_change_call_status( enabled );
  336.  
  337. status = enabled;
  338. }
  339. }
  340.  
  341. // vim:ts=4:sw=4:expandtab
Add Comment
Please, Sign In to add comment