Advertisement
Guest User

Febiansyah Hidayat

a guest
Dec 13th, 2010
201
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.02 KB | None | 0 0
  1. /*------------------------------------------------------------------------------
  2.  
  3.    Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
  4.  
  5.    Copyright (c) 2005 Nicholas Humfrey. All rights reserved.
  6.  
  7.    Tyrell DarkIce
  8.  
  9.    File     : JackDspSource.cpp
  10.    Version  : $Revision: 474 $
  11.    Author   : $Author: rafael@riseup.net $
  12.    Location : $HeadURL$
  13.    
  14.    Copyright notice:
  15.  
  16.     This program is free software; you can redistribute it and/or
  17.     modify it under the terms of the GNU General Public License  
  18.     as published by the Free Software Foundation; either version 3
  19.     of the License, or (at your option) any later version.
  20.    
  21.     This program is distributed in the hope that it will be useful,
  22.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24.     GNU General Public License for more details.
  25.    
  26.     You should have received a copy of the GNU General Public License
  27.     along with this program; if not, write to the Free Software
  28.     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  29.  
  30. ------------------------------------------------------------------------------*/
  31.  
  32. /* ============================================================ include files */
  33.  
  34. #include "AudioSource.h"
  35.  
  36. #ifdef SUPPORT_JACK_DSP
  37. // only compile this code if there is support for it
  38.  
  39. #ifdef HAVE_CONFIG_H
  40. #include "config.h"
  41. #endif
  42.  
  43. #ifdef HAVE_UNISTD_H
  44. #include <unistd.h>
  45. #else
  46. #error need unistd.h
  47. #endif
  48.  
  49. #ifdef HAVE_STRING_H
  50. #include <string.h>
  51. #else
  52. #error need string.h
  53. #endif
  54.  
  55. #ifdef HAVE_SYS_TYPES_H
  56. #include <sys/types.h>
  57. #else
  58. #error need sys/types.h
  59. #endif
  60.  
  61. #ifdef HAVE_MATH_H
  62. #include <math.h>
  63. #else
  64. #error need math.h
  65. #endif
  66.  
  67. #ifdef HAVE_STDLIB_H
  68. #include <stdlib.h>
  69. #else
  70. #error needs stdlib.h
  71. #endif
  72.  
  73. #ifdef HAVE_LIMITS_H
  74. #include <limits.h>
  75. #else
  76. #error need limits.h
  77. #endif
  78.  
  79. #include "Util.h"
  80. #include "Exception.h"
  81. #include "JackDspSource.h"
  82.  
  83.  
  84. /* ===================================================  local data structures */
  85.  
  86.  
  87. /* ================================================  local constants & macros */
  88.  
  89. /*------------------------------------------------------------------------------
  90.  *  File identity
  91.  *----------------------------------------------------------------------------*/
  92. static const char fileid[] = "$Id: JackDspSource.cpp 474 2010-05-10 01:18:15Z rafael@riseup.net $";
  93.  
  94.  
  95. /* ===============================================  local function prototypes */
  96.  
  97.  
  98. /* =============================================================  module code */
  99.  
  100. /*------------------------------------------------------------------------------
  101.  *  Initialize the object
  102.  *----------------------------------------------------------------------------*/
  103. void
  104. JackDspSource :: init ( const char* name )           throw ( Exception )
  105. {
  106.     // Set defaults
  107.     ports[0]     = NULL;        // Left Port
  108.     ports[1]     = NULL;        // Right Port
  109.     rb[0]        = NULL;        // Left Ring Buffer
  110.     rb[1]        = NULL;        // Right Ring Buffer
  111.     client       = NULL;
  112.     auto_connect = false;       // Default is to not auto connect the JACK ports
  113.     tmp_buffer   = NULL;        // Buffer big enough for one 'read' of audio
  114.  
  115.     // Auto connect the ports ?
  116.     if ( Util::strEq( name, "jack_auto", 9) ) {
  117.         auto_connect = true;
  118.     }
  119.    
  120.     // Check the sample size
  121.     if (getBitsPerSample() != 16) {
  122.         throw Exception( __FILE__, __LINE__,
  123.                         "JackDspSource doesn't support non 16-bit samples");
  124.     }
  125. }
  126.  
  127.  
  128.  
  129. /*------------------------------------------------------------------------------
  130.  *  De-initialize the object
  131.  *----------------------------------------------------------------------------*/
  132. void
  133. JackDspSource :: strip ( void )                      throw ( Exception )
  134. {
  135.     if ( isOpen() ) {
  136.         close();
  137.     }
  138.    
  139.     // Free the temporary buffer
  140.     if (tmp_buffer) {
  141.         free(tmp_buffer);
  142.         tmp_buffer = NULL;
  143.     }
  144.  
  145. }
  146.  
  147. /*------------------------------------------------------------------------------
  148.  *  Attempt to connect up the JACK ports automatically
  149.  *   - Just connect left&right to the first two output ports we find
  150.  *----------------------------------------------------------------------------*/
  151. void
  152. JackDspSource :: do_auto_connect ( void )                   throw ( Exception )
  153. {
  154.     const char **all_ports;
  155.     unsigned int ch = 0;
  156.     int          i;
  157.  
  158.     Reporter::reportEvent( 10, "JackDspSource :: do_auto_connect");
  159.    
  160.     // Get a list of all the jack ports
  161.     all_ports = jack_get_ports (client, NULL, NULL, JackPortIsOutput);
  162.     if (!ports) {
  163.         throw Exception( __FILE__, __LINE__, "jack_get_ports() returned NULL.");
  164.     }
  165.    
  166.     // Step through each port name
  167.     for (i = 0; all_ports[i]; ++i) {
  168.  
  169.         const char* in  = all_ports[i];
  170.         const char* out = jack_port_name( ports[ch] );
  171.        
  172.         Reporter::reportEvent( 2, "Connecting", in, "to", out);
  173.        
  174.         if (jack_connect(client, in, out)) {
  175.             throw Exception( __FILE__, __LINE__,
  176.                             "Failed to jack_connect() ports", in, out);
  177.         }
  178.    
  179.         // Found enough ports ?
  180.         if (++ch >= getChannel()) break;
  181.     }
  182.    
  183.     free( all_ports );
  184.  
  185. }
  186.  
  187.  
  188. /*------------------------------------------------------------------------------
  189.  *  Open the audio source
  190.  *----------------------------------------------------------------------------*/
  191. bool
  192. JackDspSource :: open ( void )                       throw ( Exception )
  193. {
  194.     char         client_name[255];
  195.     size_t       rb_size;
  196.     unsigned int c;
  197.    
  198.     if ( isOpen() ) {
  199.         return false;
  200.     }
  201.  
  202.     // Register client with Jack
  203.     if ( jack_client_name != NULL ) {
  204.       snprintf(client_name, 255, "%s", jack_client_name);
  205.     } else {
  206.       snprintf(client_name, 255, "darkice-%d", getpid());
  207.     }
  208.  
  209. //    if ((client = jack_client_new(client_name)) == NULL) {
  210. //        throw Exception( __FILE__, __LINE__, "JACK server not running?");
  211. //    }
  212.    
  213.     if ((client = jack_client_open (client_name, JackNullOption, NULL)) == 0){
  214.         throw Exception( __FILE__, __LINE__, "JACK server not running?");
  215.     }
  216.     Reporter::reportEvent( 1, "Registering as JACK client", client_name);
  217.  
  218.  
  219.     // Check the sample rate is correct
  220.     if (jack_get_sample_rate( client ) != (jack_nframes_t)getSampleRate()) {
  221.         throw Exception( __FILE__, __LINE__,
  222.                         "JACK server sample rate is different than "
  223.                         "sample rate in darkice config file");
  224.     }
  225.  
  226.  
  227.     // Register ports with Jack
  228.     if (getChannel() == 1) {
  229.         if (!(ports[0] = jack_port_register(client,
  230.                                             "mono",
  231.                                             JACK_DEFAULT_AUDIO_TYPE,
  232.                                             JackPortIsInput,
  233.                                             0))) {
  234.             throw Exception( __FILE__, __LINE__,
  235.                             "Cannot register input port", "mono");
  236.         }
  237.     } else if (getChannel() == 2) {
  238.         if (!(ports[0] = jack_port_register(client,
  239.                                             "left",
  240.                                             JACK_DEFAULT_AUDIO_TYPE,
  241.                                             JackPortIsInput,
  242.                                             0))) {
  243.             throw Exception( __FILE__, __LINE__,
  244.                             "Cannot register input port", "left");
  245.         }
  246.         if (!(ports[1] = jack_port_register(client,
  247.                                             "right",
  248.                                             JACK_DEFAULT_AUDIO_TYPE,
  249.                                             JackPortIsInput, 0))) {
  250.             throw Exception( __FILE__, __LINE__,
  251.                             "Cannot register input port", "right");
  252.         }
  253.     } else {
  254.         throw Exception( __FILE__, __LINE__,
  255.                         "Invalid number of channels", getChannel());
  256.     }
  257.  
  258.  
  259.     // Create a ring buffer for each channel
  260.     rb_size = 2
  261.             * jack_get_sample_rate(client)
  262.             * sizeof (jack_default_audio_sample_t);
  263.     for (c=0; c<getChannel(); c++) {
  264.         rb[c] = jack_ringbuffer_create(rb_size);
  265.         if (!rb[c]) {
  266.             throw Exception( __FILE__, __LINE__,
  267.                             "Failed to create ringbuffer for", "channel", c);
  268.         }
  269.     }
  270.  
  271.  
  272.     // Set the callbacks
  273.     jack_on_shutdown(client, JackDspSource::shutdown_callback, (void*)this);
  274.     if (jack_set_process_callback(client,
  275.                                   JackDspSource::process_callback,
  276.                                   (void*)this)) {
  277.         throw Exception( __FILE__, __LINE__, "Failed to set process callback");
  278.     }    
  279.  
  280.     // Activate client
  281.     if (jack_activate(client)) {
  282.         throw Exception( __FILE__, __LINE__, "Can't activate client");
  283.     }
  284.    
  285.     // Attempt to automatically connect up our input ports to something ?
  286.     if (auto_connect) {
  287.         do_auto_connect();
  288.     }
  289.    
  290.     return true;
  291. }
  292.  
  293.  
  294. /*------------------------------------------------------------------------------
  295.  *  Check wether read() would return anything
  296.  *----------------------------------------------------------------------------*/
  297. bool
  298. JackDspSource :: canRead ( unsigned int   sec,
  299.                            unsigned int   usec )    throw ( Exception )
  300. {
  301.     const unsigned int max_wait_time  = sec * 1000000;
  302.     const unsigned int wait_increment = 10000;
  303.     unsigned int       cur_wait       = 0;
  304.  
  305.     if ( !isOpen() ) {
  306.         return false;
  307.     }
  308.  
  309.     while (max_wait_time > cur_wait) {
  310.         bool canRead = true;
  311.  
  312.         for (unsigned int c = 0 ; c < getChannel() ; c++) {
  313.             if (jack_ringbuffer_read_space(rb[c]) <= 0) {
  314.                 canRead = false;
  315.             }
  316.         }
  317.  
  318.         if (canRead) {
  319.             return true;
  320.         }
  321.  
  322.         cur_wait += wait_increment;
  323.         usleep ( wait_increment );
  324.     }
  325.  
  326.     usleep( usec );
  327.     for (unsigned int c = 0 ; c < getChannel() ; c++) {
  328.         if (jack_ringbuffer_read_space(rb[c]) <= 0) {
  329.             return false;
  330.         }
  331.     }
  332.  
  333.     return true;
  334. }
  335.  
  336.  
  337. /*------------------------------------------------------------------------------
  338.  *  Read from the audio source
  339.  *----------------------------------------------------------------------------*/
  340. unsigned int
  341. JackDspSource :: read (   void          * buf,
  342.                           unsigned int    len )     throw ( Exception )
  343. {
  344.     jack_nframes_t samples         = len / 2 / getChannel();
  345.     jack_nframes_t samples_read[2] = {0,0};
  346.     short        * output          = (short*)buf;
  347.     unsigned int c, n;
  348.  
  349.     if ( !isOpen() ) {
  350.         return 0;
  351.     }
  352.  
  353.  
  354.     // Ensure the temporary buffer is big enough
  355.     tmp_buffer = (jack_default_audio_sample_t*)realloc(tmp_buffer,
  356.                              samples * sizeof( jack_default_audio_sample_t ) );
  357.     if (!tmp_buffer) {
  358.         throw Exception( __FILE__, __LINE__, "realloc on tmp_buffer failed");
  359.     }
  360.  
  361.     // We must be sure to fetch as many data on both channels
  362.     int minBytesAvailable = samples * sizeof( jack_default_audio_sample_t );
  363.  
  364.     for (c=0; c<getChannel(); c++) {
  365.         int readable = jack_ringbuffer_read_space(rb[c]);
  366.         if (readable < minBytesAvailable) {
  367.             minBytesAvailable = readable;
  368.         }
  369.     }
  370.  
  371.     for (c=0; c<getChannel(); c++) {    
  372.         // Copy frames from ring buffer to temporary buffer
  373.         // and then convert samples to output buffer
  374.         int bytes_read = jack_ringbuffer_read(rb[c],
  375.                                              (char*)tmp_buffer,
  376.                               minBytesAvailable);
  377.         samples_read[c] = bytes_read / sizeof( jack_default_audio_sample_t );
  378.        
  379.  
  380.         // Convert samples from float to short and put in output buffer
  381.         for(n=0; n<samples_read[c]; n++) {
  382.             int tmp = lrintf(tmp_buffer[n] * 32768.0f);
  383.             if (tmp > SHRT_MAX) {
  384.                 output[n*getChannel()+c] = SHRT_MAX;
  385.             } else if (tmp < SHRT_MIN) {
  386.                 output[n*getChannel()+c] = SHRT_MIN;
  387.             } else {
  388.                 output[n*getChannel()+c] = (short) tmp;
  389.             }
  390.         }
  391.     }
  392.  
  393.     // Didn't get as many samples as we wanted ?
  394.     if (getChannel() == 2 && samples_read[0] != samples_read[1]) {
  395.         Reporter::reportEvent( 2,
  396.                               "Warning: Read a different number of samples "
  397.                               "for left and right channels");
  398.     }
  399.  
  400.     // Return the number of bytes put in the output buffer
  401.     return samples_read[0] * 2 * getChannel();
  402. }
  403.  
  404.  
  405. /*------------------------------------------------------------------------------
  406.  *  Close the audio source
  407.  *----------------------------------------------------------------------------*/
  408. void
  409. JackDspSource :: close ( void )                  throw ( Exception )
  410. {
  411.     unsigned int i;
  412.  
  413.     if ( !isOpen() ) {
  414.         return;
  415.     }
  416.  
  417.     for(i = 0; i < getChannel(); i++) {
  418.         // Close the port for channel
  419.         if ( ports[i] ) {
  420.             jack_port_unregister( client, ports[i] );
  421.             ports[i] = NULL;
  422.         }
  423.        
  424.         // Free up the ring buffer for channel
  425.         if ( rb[i] ) {
  426.             jack_ringbuffer_free( rb[i] );
  427.             rb[i] = NULL;
  428.         }
  429.     }
  430.  
  431.     /* Leave the jack graph */
  432.     if (client) {
  433.         jack_client_close(client);
  434.         client = NULL;
  435.     }
  436.  
  437. }
  438.  
  439.  
  440. /*------------------------------------------------------------------------------
  441.  *  Callback called by JACK when audio is available
  442.  *
  443.  *  Don't do anything too expensive here
  444.  *      - just shove audio samples in ring buffer
  445.  *----------------------------------------------------------------------------*/
  446. int
  447. JackDspSource :: process_callback( jack_nframes_t nframes, void *arg )
  448. {
  449.     JackDspSource* self     = (JackDspSource*)arg;
  450.     size_t         to_write = sizeof (jack_default_audio_sample_t) * nframes;
  451.     unsigned int   c;
  452.    
  453.     // Wait until it is ready
  454.     if (self->client == NULL) {
  455.         return 0;
  456.     }
  457.  
  458.     /* copy data to ringbuffer; one per channel */
  459.     for (c=0; c < self->getChannel(); c++) {    
  460.         char *buf  = (char*)jack_port_get_buffer(self->ports[c], nframes);
  461.         size_t len = jack_ringbuffer_write(self->rb[c], buf, to_write);
  462.         if (len < to_write) {
  463.             Reporter::reportEvent( 1, "failed to write to ring ruffer");
  464.             return 1;
  465.          }
  466.     }
  467.  
  468.     // Success
  469.     return 0;
  470. }
  471.  
  472. /*------------------------------------------------------------------------------
  473.  *  Callback called when
  474.  *----------------------------------------------------------------------------*/
  475. void
  476. JackDspSource :: shutdown_callback( void *arg )
  477. {
  478.     //JackDspSource* self = (JackDspSource*)arg;
  479.  
  480.     Reporter::reportEvent( 1, "JackDspSource :: shutdown_callback");
  481. }
  482.  
  483.  
  484. #endif // SUPPORT_JACK_DSP
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement