Page Example

(Tutorial) Audio IO_3.0 Sample Overview

Mobile native

The Audio I/O sample application demonstrates how to use the Audio I/O and Sound Manager APIs to record and play synchronous or asynchronous audio. You can also increase the volume of the recorded synchronous audio during playback. In synchronous audio, the recording and playback duration is predefined with the RECORDING_SEC variable.

The following figure illustrates the main view of the Audio I/O application.

Figure: Audio I/O main view

Audio I/O main view

Source Files

You can create and view the sample application project, including the source files, in the IDE.

Table: Source files
File name Description
inc/data.h This file contains the variable and function definitions used in the C files, especially in the data.c file.
inc/main.h This file contains the package name and log declarations.
inc/view.h This file contains the variable and function definitions used in the C files, especially in the view.c file.
src/data.c This file contains the functions for retrieving and making data for the application.
src/main.c This file contains the functions related to the application life-cycle, event callbacks, and view controls.
src/view.c This file contains the functions for implementing the views and handling events.

Implementation

To implement audio I/O:
  1. In the data.c file, the data_initialize() and data_finalize() functions initialize and finalize the data module. The data_initialize() function creates the stream information and registers the focus callback function using the Sound Manager API. It also initializes the audio device and sets the path for the recorded audio file. The data_finalize() function destroys the stream information.
  2. To create the application main view:
    1. In the view_create() function, create the window and conformant:
      void
      view_create(void)
      {
          /* Create the window */
          s_info.win = view_create_win(PACKAGE);
          if (s_info.win == NULL) {
              dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a window.");
      
              return;
          }
      
          /* Create the conformant */
          s_info.conform = view_create_conformant_without_indicator(s_info.win);
          if (s_info.conform == NULL) {
              dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a conformant");
      
              return;
          }
      
          /* Create buttons for the application */
          create_buttons_in_main_window();
      
          /* Show the window after the main view is set up */
          evas_object_show(s_info.win);
      }
      
    2. The create_buttons_in_main_window() function creates the buttons for audio I/O:
      void
      create_buttons_in_main_window()
      {
          /* Create the window */
          Evas_Object *display = _create_new_cd_display("Audio I/O", NULL);
      
          /* Create the buttons */
          g_audio_sync_rec_button = _new_button(display, "Synchronous Recording",
                                                __audioIO_cb_record);
          g_audio_sync_play_button = _new_button(display, "Synchronous Playback",
                                                 __audioIO_cb_play);
          g_audio_sync_vol_button = _new_button(display, "Sync Recording Volume Up",
                                                __audioIO_cb_modify);
          g_audio_async_rec_button = _new_button(display, "Start Asynchronous Recording",
                                                 __audioIO_cb_recordasync);
          g_audio_async_play_button = _new_button(display, "Start Asynchronous Playback",
                                                  __audioIO_cb_playasync);
      
          /* Disable playback and volume buttons because there is no recording yet */
          elm_object_disabled_set(g_audio_sync_play_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_sync_vol_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_async_play_button, EINA_TRUE);
      }
      
  3. The application operations are activated when the user clicks the buttons on the main view:
    • When the user clicks Synchronous Recording, run the synchronous_recording thread. In the thread, acquire the sound stream focus for recording using the Sound Manager API and start recording using the Audio I/O API.
      static void
      __audioIO_cb_record(void *data, Evas_Object *obj, void *event_info)
      {
          PRINT_MSG("Synchronous recording starts.");
      
          /* Disable buttons until the synchronous recording finishes */
          elm_object_disabled_set(g_audio_sync_rec_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_sync_play_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_sync_vol_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_async_rec_button, EINA_TRUE);
      
          /*
             Launch synchronous recording in a different thread to prevent
             blocking the application main loop
          */
          ecore_thread_run(synchronous_recording, synchronous_recording_ended, NULL, NULL);
      }
      

      Recording stops after the duration defined by the RECORDING_SEC variable.

    • When the user clicks Synchronous Playback, run the synchronous_playback thread. In the thread, acquire the sound stream focus for playback using the Sound Manager API and start playback using the Audio I/O API.
      void
      __audioIO_cb_play(void *data, Evas_Object *obj, void *event_info)
      {
          PRINT_MSG("Synchronous playback starts.");
      
          /* Disable buttons until the synchronous playback finishes */
          elm_object_disabled_set(g_audio_sync_play_button, EINA_TRUE);
          elm_object_disabled_set(g_audio_sync_rec_button, EINA_TRUE);
      
          /*
             Launch synchronous playback in a different thread to prevent
             blocking the application main loop
          */
          ecore_thread_run(synchronous_playback, synchronous_playback_ended, NULL, NULL);
      }
      
    • When the user clicks Sync Recording Volume Up, increase the volume of the recorded PCM sample:
      void
      __audioIO_cb_modify(void *data, Evas_Object *obj, void *event_info)
      {
          int error_code = AUDIO_IO_ERROR_NONE;
      
          /* Get the sample type of the input */
          audio_sample_type_e sample_type;
      
          error_code = audio_in_get_sample_type(g_input, &sample_type);
          CHECK_ERROR_AND_RETURN("audio_in_get_sample_type", error_code);
      
          uint8_t *index = (uint8_t *) g_buffer;
      
          while (index < (((uint8_t *) g_buffer) + g_buffer_size)) {
              if (AUDIO_SAMPLE_TYPE_S16_LE == sample_type) {
                  /* int16_t type is used when the sample is 2 bytes long */
                  int16_t *value = (int16_t *) index;
      
                  /* Make the sample louder */
                  int32_t tmp = (*value) * 8;
      
                  if (tmp > MAX_2BYTES_SIGNED)
                      tmp = MAX_2BYTES_SIGNED;
      
                  if (tmp < MIN_2BYTES_SIGNED)
                      tmp = MIN_2BYTES_SIGNED;
                  (*value) = tmp;
              } else {
                  /* uint8_t type is used when the sample is 1 byte long */
                  uint8_t *value = (uint8_t *) index;
      
                  /* Make the sample louder */
                  uint16_t tmp = (*value) * 8;
      
                  if (tmp > 255)
                      tmp = 255;
      
                  (*value) = tmp;
              }
              /* Go to next sample */
              index += sample_type == AUDIO_SAMPLE_TYPE_S16_LE ? 2 : 1;
          }
      }
      
    • When the user clicks Start Asynchronous Recording, acquire the sound stream focus for recording using the Sound Manager API, and start recording using the Audio I/O API:
      static void
      __audioIO_cb_recordasync(void *data, Evas_Object *obj, void *event_info)
      {
          int error_code = AUDIO_IO_ERROR_NONE;
      
          if (!is_async_rec_ongoing) {
              /*
                 Set a callback function to be called asynchronously
                 for each part of the captured audio data
              */
              error_code = audio_in_set_stream_cb(g_input, _audio_io_stream_read_cb, NULL);
              CHECK_ERROR_AND_RETURN("audio_in_set_stream_cb", error_code);
      
              /* Open the file for storing the recorded data */
              g_fp_w = fopen(g_audio_io_file_path, "w");
      
              if (g_fp_w)
                  PRINT_MSG("Recording stored in %s file.", g_audio_io_file_path);
              else {
                  DLOG_PRINT_ERROR("fopen", g_fp_w);
      
                  return;
              }
              /* Acquire recording focus before starting the recording */
              error_code = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_RECORDING,
                                                       SOUND_BEHAVIOR_NONE, "SampleAppAudioIO(Acquire)");
              if (SOUND_MANAGER_ERROR_NONE != error_code)
                  dlog_print(DLOG_ERROR, LOG_TAG,
                             "sound_manager_acquire_focus() failed! Error code = %d", error_code);
              CHECK_ERROR_AND_RETURN("sound_manager_acquire_focus", error_code);
              g_current_state = ASYNC_RECORD;
      
              /* Prepare audio input (start the hardware recording process) */
              error_code = audio_in_prepare(g_input);
              if (AUDIO_IO_ERROR_NONE != error_code) {
                  DLOG_PRINT_ERROR("audio_in_prepare", error_code);
              } else {
                  PRINT_MSG("Asynchronous recording started.");
                  is_async_rec_ongoing = true;
      
                  /* Disable buttons until the asynchronous recording finishes */
                  elm_object_disabled_set(g_audio_async_play_button, EINA_TRUE);
                  elm_object_disabled_set(g_audio_sync_rec_button, EINA_TRUE);
              }
      
              elm_object_text_set(g_audio_async_rec_button, "Stop Asynchronous Recording");
          } else {
              /* Stop the hardware recording process */
              error_code = audio_in_unprepare(g_input);
              if (AUDIO_IO_ERROR_NONE != error_code) {
                  DLOG_PRINT_ERROR("audio_in_unprepare", error_code);
              } else {
                  PRINT_MSG("Asynchronous recording stopped.");
                  is_async_rec_ongoing = false;
      
                  /* Release the focus if callback is not invoked */
                  if (!g_focus_cb_invoked_async_record) {
                      error_code = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_RECORDING,
                                                               SOUND_BEHAVIOR_NONE, "SampleAppAudioIO(Release)");
                      if (SOUND_MANAGER_ERROR_NONE != error_code)
                          dlog_print(DLOG_ERROR, LOG_TAG,
                                     "sound_manager_release_focus() failed! Error code = %d", error_code);
                      CHECK_ERROR("sound_manager_release_focus", error_code);
                  }
                  g_current_state = NONE;
      
                  g_focus_cb_invoked_async_record = 0;
                  /* Enable buttons when asynchronous recording is finished */
                  elm_object_disabled_set(g_audio_async_play_button, EINA_FALSE);
                  elm_object_disabled_set(g_audio_sync_rec_button, EINA_FALSE);
      
                  /* Unset the callback function used for asynchronous recording process */
                  error_code = audio_in_unset_stream_cb(g_input);
                  CHECK_ERROR("audio_in_unset_stream_cb", error_code);
      
                  /* Close the file used for recording */
                  error_code = fclose(g_fp_w);
                  CHECK_ERROR("fclose", error_code);
      
                  elm_object_text_set(g_audio_async_rec_button, "Start Asynchronous Recording");
              }
          }
      }
      
    • When the user clicks Start Asynchronous Playback, acquire the sound stream focus for playback using the Sound Manager API, and start playback using the Audio I/O API:
      static void
      __audioIO_cb_playasync(void *data, Evas_Object *obj, void *event_info)
      {
          int error_code = AUDIO_IO_ERROR_NONE;
      
          if (!is_async_play_ongoing) {
              /*
                 Set a callback function to be called asynchronously
                 for each part of the stored audio data
              */
              error_code = audio_out_set_stream_cb(g_output, _audio_io_stream_write_cb, NULL);
              CHECK_ERROR_AND_RETURN("audio_out_set_stream_cb", error_code);
      
              /* Open the file for playback */
              g_fp_r = fopen(g_audio_io_file_path, "r");
      
              /* Acquire playback focus before starting playback */
              error_code = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK,
                                                       SOUND_BEHAVIOR_NONE, "SampleAppAudioIO(Acquire)");
              if (SOUND_MANAGER_ERROR_NONE != error_code)
                  dlog_print(DLOG_ERROR, LOG_TAG,
                             "sound_manager_acquire_focus() failed! Error code = %d", error_code);
              CHECK_ERROR_AND_RETURN("sound_manager_acquire_focus", error_code);
              g_current_state = ASYNC_PLAYBACK;
      
              /* Prepare audio output (start the hardware playback process) */
              error_code = audio_out_prepare(g_output);
              if (AUDIO_IO_ERROR_NONE != error_code) {
                  DLOG_PRINT_ERROR("audio_out_prepare", error_code);
              } else {
                  PRINT_MSG("Asynchronous playback started.");
                  is_async_play_ongoing = true;
      
                  /* Disable "Asynchronous Recording" button until playback finishes */
                  elm_object_disabled_set(g_audio_async_rec_button, EINA_TRUE);
              }
              elm_object_text_set(g_audio_async_play_button, "Stop Asynchronous Playback");
          } else {
              /* Stop the hardware playback process */
              error_code = audio_out_unprepare(g_output);
              if (AUDIO_IO_ERROR_NONE != error_code) {
                  DLOG_PRINT_ERROR("audio_out_unprepare", error_code);
              } else {
                  PRINT_MSG("Asynchronous playback stopped.");
                  is_async_play_ongoing = false;
                  if (!g_focus_cb_invoked_async_playback) {
                      error_code = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_PLAYBACK,
                                                               SOUND_BEHAVIOR_NONE, "SampleAppAudioIO(Release)");
                      if (SOUND_MANAGER_ERROR_NONE != error_code)
                          dlog_print(DLOG_ERROR, LOG_TAG,
                                     "sound_manager_release_focus() failed! Error code = %d", error_code);
                      CHECK_ERROR("sound_manager_release_focus", error_code);
                  }
      
                  g_current_state = NONE;
                  g_focus_cb_invoked_async_playback = 0;
      
                  /* Enable "Asynchronous Recording" button when playback is finished */
                  elm_object_disabled_set(g_audio_async_rec_button, EINA_FALSE);
      
                  /* Unset the callback function used for asynchronous playback process */
                  error_code = audio_out_unset_stream_cb(g_output);
                  CHECK_ERROR("audio_out_unset_stream_cb", error_code);
      
                  /* Close the file used for playback */
                  error_code = fclose(g_fp_r);
                  CHECK_ERROR("fclose", error_code);
      
                  elm_object_text_set(g_audio_async_play_button, "Start Asynchronous Playback");
              }
          }
      }