PulseAudio example

PulseAudio APIs

pa_simple_new
pa_simple_write
pa_simple_drain
pa_simple_free
https://freedesktop.org/software/pulseaudio/doxygen/examples.html

build command

gcc -o pulse pulse.c `pkg-config --cflags --libs libpulse-simple`

source

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#define BUFSIZE 1024
int main(int argc, char* argv[]) {
  /* The Sample format to use */
  static const pa_sample_spec ss = {
      .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2};
  pa_simple* s = NULL;
  int ret = 1;
  int error;
  /* replace STDIN with the specified file if needed */
  if (argc > 1) {
    int fd;
    if ((fd = open(argv[1], O_RDONLY)) < 0) {
      fprintf(stderr, __FILE__ ": open() failed: %s\n", strerror(errno));
      goto finish;
    }
    if (dup2(fd, STDIN_FILENO) < 0) {
      fprintf(stderr, __FILE__ ": dup2() failed: %s\n", strerror(errno));
      goto finish;
    }
    close(fd);
  }
  /* Create a new playback stream */
  if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback",
                          &ss, NULL, NULL, &error))) {
    fprintf(stderr, __FILE__ ": pa_simple_new() failed: %s\n",
            pa_strerror(error));
    goto finish;
  }
  for (;;) {
    uint8_t buf[BUFSIZE];
    ssize_t r;
#if 0
        pa_usec_t latency;
        if ((latency = pa_simple_get_latency(s, &error)) == (pa_usec_t) -1) {
            fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
            goto finish;
        }
        fprintf(stderr, "%0.0f usec    \r", (float)latency);
#endif
    /* Read some data ... */
    if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) {
      if (r == 0) /* EOF */
        break;
      fprintf(stderr, __FILE__ ": read() failed: %s\n", strerror(errno));
      goto finish;
    }
    /* ... and play it */
    if (pa_simple_write(s, buf, (size_t)r, &error) < 0) {
      fprintf(stderr, __FILE__ ": pa_simple_write() failed: %s\n",
              pa_strerror(error));
      goto finish;
    }
  }
  /* Make sure that every single sample was played */
  if (pa_simple_drain(s, &error) < 0) {
    fprintf(stderr, __FILE__ ": pa_simple_drain() failed: %s\n",
            pa_strerror(error));
    goto finish;
  }
  ret = 0;
finish:
  if (s)
    pa_simple_free(s);
  return ret;
}

 

alsa programing example

alsa APIs

snd_pcm_open
snd_pcm_hw_params_set_format
snd_pcm_prepare
snd_pcm_writei
snd_pcm_drain
snd_pcm_close
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html

issues

If your device can't support mixer feature, or pcm interface can't open multi times.
You can try PulseAudio.
pulseaudio example

compile cmd

gcc -o play play.c `pkg-config --cflags --libs alsa`

source

#include <alsa/asoundlib.h>
#include <stdio.h>

#define PCM_DEVICE "default"

int main(int argc, char** argv) {
  unsigned int pcm, tmp, dir;
  int rate, channels, seconds;
  snd_pcm_t* pcm_handle;
  snd_pcm_hw_params_t* params;
  snd_pcm_uframes_t frames;
  char* buff;
  int buff_size, loops;

  if (argc < 4) {
    printf("Usage: %s <sample_rate> <channels> <seconds>\n", argv[0]);
    return -1;
  }

  rate = atoi(argv[1]);
  channels = atoi(argv[2]);
  seconds = atoi(argv[3]);

  /* Open the PCM device in playback mode */
  if (pcm =
          snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0)
    printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE,
           snd_strerror(pcm));

  /* Allocate parameters object and fill it with default values*/
  snd_pcm_hw_params_alloca(&params);

  snd_pcm_hw_params_any(pcm_handle, params);

  /* Set parameters */
  if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params,
                                         SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
    printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));

  if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params,
                                         SND_PCM_FORMAT_S16_LE) < 0)
    printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));

  if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0)
    printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));

  if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0)
    printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));

  /* Write parameters */
  if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0)
    printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));

  /* Resume information */
  printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));

  printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));

  snd_pcm_hw_params_get_channels(params, &tmp);
  printf("channels: %i ", tmp);

  if (tmp == 1)
    printf("(mono)\n");
  else if (tmp == 2)
    printf("(stereo)\n");

  snd_pcm_hw_params_get_rate(params, &tmp, 0);
  printf("rate: %d bps\n", tmp);

  printf("seconds: %d\n", seconds);

  /* Allocate buffer to hold single period */
  snd_pcm_hw_params_get_period_size(params, &frames, 0);

  buff_size = frames * channels * 2 /* 2 -> sample size */;
  buff = (char*)malloc(buff_size);

  snd_pcm_hw_params_get_period_time(params, &tmp, NULL);

  for (loops = (seconds * 1000000) / tmp; loops > 0; loops--) {
    if (pcm = read(0, buff, buff_size) == 0) {
      printf("Early end of file.\n");
      return 0;
    }

    printf("write data\n");
    if (pcm = snd_pcm_writei(pcm_handle, buff, frames) == -EPIPE) {
      printf("XRUN.\n");
      snd_pcm_prepare(pcm_handle);
    } else if (pcm < 0) {
      printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm));
    }
  }

  snd_pcm_drain(pcm_handle);
  snd_pcm_close(pcm_handle);
  free(buff);

  return 0;
}

fix autoconf error : possibly undefined macro: AC_SEARCH_LIBS

configure.ac:109: error: possibly undefined macro: AC_SEARCH_LIBS
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
autoreconf: /usr/local/bin/autoconf failed with exit status: 1
autoreconf failed

solution

sudo apt install libtool

notes, all below should be installed

autoconf automake m4 libtool libevent perl pkg-config 

How to install nvidia drivers on ubuntu

First update your new system

sudo apt-get update 
sudo apt-get dist-upgrade 

ensure what graphics driver your system needs.

ubuntu-drivers devices 

install intel driver first

sudo apt-get install intel-microcode 
sudo apt-get install nvidia-xxx 
That's all.

Note: nvidia-xxx

you must enter the recommended driver version displayed in ubuntu-drivers devices and I must warn you. Updating the kernel may cause you problems, so once you installed that NVIDIA driver, please don't upgrade with this commands (sudo apt dist-upgrade or sudo apt upgrade and sudo apt-get dist-upgrade), please use sudo apt-get upgrade that command will hold new kernel releases.

Running EFL applications under Wayland based on Ubuntu 14.04 : egl wayland example

For correct functionality when running under Wayland you must use the latest versions of all the EFL components under Wayland. As a precursor to these steps you must have downloaded and compiled Wayland as per the building instructions.

example codes

// gcc -o eglwayland eglwayland.c  `pkg-config --cflags --libs wayland-egl egl glesv2`
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-client-protocol.h>
#include <wayland-egl.h> // Wayland EGL MUST be included before EGL headers

#include <EGL/egl.h>
#include <EGL/eglplatform.h>
#include <GLES2/gl2.h>

struct _escontext
{
  /// Native System informations
  EGLNativeDisplayType native_display;
  EGLNativeWindowType native_window;
  uint16_t window_width, window_height;
  /// EGL display
  EGLDisplay  display;
  /// EGL context
  EGLContext  context;
  /// EGL surface
  EGLSurface  surface;

};

void CreateNativeWindow(char* title, int width, int height);
EGLBoolean CreateEGLContext();
EGLBoolean CreateWindowWithEGLContext(char *title, int width, int height);
void RefreshWindow();

struct wl_compositor *compositor = NULL;
struct wl_surface *surface;
struct wl_egl_window *egl_window;
struct wl_region *region;
struct wl_shell *shell;
struct wl_shell_surface *shell_surface;

struct _escontext ESContext = {
  .native_display = NULL,
  .window_width = 0,
  .window_height = 0,
  .native_window  = 0,
  .display = NULL,
  .context = NULL,
  .surface = NULL
};

#define TRUE 1
#define FALSE 0

#define WINDOW_WIDTH 1920
#define WINDOW_HEIGHT 1080

void CreateNativeWindow(char *title, int width, int height) {

  region = wl_compositor_create_region(compositor);

  wl_region_add(region, 0, 0, width, height);
  wl_surface_set_opaque_region(surface, region);

  struct wl_egl_window *egl_window =
    wl_egl_window_create(surface, width, height);

  if (egl_window == EGL_NO_SURFACE) {
    printf("No window !?\n");
    exit(1);
  }
  else printf("Window created !\n");
  ESContext.window_width = width;
  ESContext.window_height = height;
  ESContext.native_window = egl_window;

}
EGLBoolean CreateEGLContext ()
{
   EGLint numConfigs;
   EGLint majorVersion;
   EGLint minorVersion;
   EGLContext context;
   EGLSurface surface;
   EGLConfig config;

  EGLint attribute_list[] = {EGL_SURFACE_TYPE,    // this must be first
                             EGL_WINDOW_BIT | EGL_PBUFFER_BIT
                             ,
                             EGL_RED_SIZE,
                             8,
                             EGL_GREEN_SIZE,
                             8,
                             EGL_BLUE_SIZE,
                             8,
                             EGL_ALPHA_SIZE,
                             8,
                             EGL_BIND_TO_TEXTURE_RGBA,
                             EGL_TRUE,
                             EGL_RENDERABLE_TYPE,
                             EGL_OPENGL_ES2_BIT,
                             EGL_NONE};

   EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
   EGLDisplay display = eglGetDisplay( ESContext.native_display );
   if ( display == EGL_NO_DISPLAY )
   {
      printf("No EGL Display...\n");
      return EGL_FALSE;
   }

   // Initialize EGL
   if ( !eglInitialize(display, &majorVersion, &minorVersion) )
   {
      printf("No Initialisation... %d \n", eglGetError());
      return EGL_FALSE;
   }

   // Get configs
   if ( (eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0))
   {
      printf("No get configuration...\n");
      return EGL_FALSE;
   }

   // Choose config
   if ( (eglChooseConfig(display, attribute_list, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1))
   {
      printf("No choose configuration...\n");
      return EGL_FALSE;
   }

   // Create a surface
   surface = eglCreateWindowSurface(display, config, ESContext.native_window, NULL);
   if ( surface == EGL_NO_SURFACE )
   {
      printf("No surface...\n");
      return EGL_FALSE;
   }

   // Create a GL context
   context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
   if ( context == EGL_NO_CONTEXT )
   {
      printf("No context...\n");
      return EGL_FALSE;
   }

   // Make the context current
   if ( !eglMakeCurrent(display, surface, surface, context) )
   {
      printf("Could not make the current window current !\n");
      return EGL_FALSE;
   }

   printf("Context created \n");
   ESContext.display = display;
   ESContext.surface = surface;
   ESContext.context = context;
   return EGL_TRUE;
}

void shell_surface_ping
(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) {
  wl_shell_surface_pong(shell_surface, serial);
}

void shell_surface_configure
(void *data, struct wl_shell_surface *shell_surface, uint32_t edges,
 int32_t width, int32_t height) {
  struct window *window = data;
  wl_egl_window_resize(ESContext.native_window, width, height, 0, 0);
}

void shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface) {
}

static struct wl_shell_surface_listener shell_surface_listener = {
  &shell_surface_ping,
  &shell_surface_configure,
  &shell_surface_popup_done
};

EGLBoolean CreateWindowWithEGLContext(char *title, int width, int height) {
  CreateNativeWindow(title, width, height);
  return CreateEGLContext();
}

void draw() {
  glClearColor(0.7, 0.1, 0.5, 0.2);
  glClear(GL_COLOR_BUFFER_BIT);
}

unsigned long last_click = 0;
void RefreshWindow() { eglSwapBuffers(ESContext.display, ESContext.surface); }

static void global_registry_handler
(void *data, struct wl_registry *registry, uint32_t id,
 const char *interface, uint32_t version) {
  printf("Got a registry event for %s id %d\n", interface, id);
  if (strcmp(interface, "wl_compositor") == 0)
    compositor =
      wl_registry_bind(registry, id, &wl_compositor_interface, 1);

  else if (strcmp(interface, "wl_shell") == 0)
    shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
}

static void global_registry_remover
(void *data, struct wl_registry *registry, uint32_t id) {
  printf("Got a registry losing event for %d\n", id);
}

const struct wl_registry_listener listener = {
  global_registry_handler,
  global_registry_remover
};

static void
get_server_references() {

  struct wl_display * display = wl_display_connect(NULL);
  if (display == NULL) {
    printf("Can't connect to wayland display !?\n");
    exit(1);
  }
  printf("Got a display !");

  struct wl_registry *wl_registry =
    wl_display_get_registry(display);
  wl_registry_add_listener(wl_registry, &listener, NULL);

  // This call the attached listener global_registry_handler
  wl_display_dispatch(display);
  wl_display_roundtrip(display);

  // If at this point, global_registry_handler didn't set the 
  // compositor, nor the shell, bailout !
  if (compositor == NULL || shell == NULL) {
    printf("No compositor !? No Shell !! There's NOTHING in here !\n");
    exit(1);   
  }
  else {
    printf("Okay, we got a compositor and a shell... That's something !\n");
    ESContext.native_display = display;
  }
}

void destroy_window() {
  eglDestroySurface(ESContext.display, ESContext.surface);
  wl_egl_window_destroy(ESContext.native_window);
  wl_shell_surface_destroy(shell_surface);
  wl_surface_destroy(surface);
  eglDestroyContext(ESContext.display, ESContext.context);
}

int main() {
  get_server_references();

  surface = wl_compositor_create_surface(compositor);
  if (surface == NULL) {
    printf("No Compositor surface ! Yay....\n");
    exit(1);
  }
  else printf("Got a compositor surface !\n");

  shell_surface = wl_shell_get_shell_surface(shell, surface);
  wl_shell_surface_set_toplevel(shell_surface);

  if (!CreateWindowWithEGLContext("Nya", 1280, 720)) {
    printf("Fail create EGL Context\n");
    exit(0);
  }

  while (1) {
    wl_display_dispatch_pending(ESContext.native_display);
    draw();
    RefreshWindow();
  }

  wl_display_disconnect(ESContext.native_display);
  printf("Display disconnected !\n");

  exit(0);
}

compile command

source env.sh
gcc -o eglwayland eglwayland.c pkg-config --cflags --libs wayland-egl egl glesv2

start weston

weston &

run example

./eglwayland
eglwayland

notes

egl APIs normal usage:
eglGetDisplay
eglInitialize
eglChooseConfig
eglCreateWindowSurface
eglCreateContext
eglMakeCurrent
// gl draw
// gl draw
eglSwapBuffers

Running EFL applications under Wayland based on Ubuntu 14.04 : elm example

For correct functionality when running under Wayland you must use the latest versions of all the EFL components under Wayland. As a precursor to these steps you must have downloaded and compiled Wayland as per the building instructions.

example codes

#include <Elementary.h>

static void
on_click(void *data, Evas_Object *obj, void *event_info)
{
   evas_object_del(data);
}

EAPI_MAIN int
elm_main(int argc, char **argv)
{
   Evas_Object *win, *btn;

   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   win = elm_win_util_standard_add("Main", "Hello, World!");
   evas_object_resize(win, 1920, 1080);
   elm_win_autodel_set(win, EINA_TRUE);

   btn = elm_button_add(win);
   elm_object_text_set(btn, "Goodbye Cruel World");
   elm_win_resize_object_add(win, btn);
   evas_object_smart_callback_add(btn, "clicked", on_click, win);
   evas_object_show(btn);

   evas_object_show(win);

   elm_run();

   return 0;
}
ELM_MAIN()

compile command

source env.sh
gcc -o elm elm.c pkg-config --cflags --libs elementary

start weston

weston &

run example

./elm
elm

notes

Running EFL applications under Wayland
For applications that use Ecore_Evas directly set the environment variable ECORE_EVAS_ENGINE to either wayland_shm or wayland_egl depending on whether you wish to use the SHM based interface with software rendering or use EGL.
For applications that use Elementary set the environment variable ELM_DISPLAY to wl. You may also set the environment variable ELM_ACCEL to none to use software rendering, or to gl to use hardware accelerated rendering.
For more debug info, please set:
export MESA_DEBUG=1
export EGL_LOG_LEVEL=debug
export LIBGL_DEBUG=verbose
export WAYLAND_DEBUG=1

Running EFL applications under Wayland based on Ubuntu 14.04, compile libdrm, mesa, wayland, weston, efl from sources

For correct functionality when running under Wayland you must use the latest versions of all the EFL components under Wayland. As a precursor to these steps you must have downloaded and compiled Wayland.

Setting up the environment

apt install git autoconf automake libtool autopoint check
Installing in a custom location, system wide install would break things.
export WLD=$HOME/install   # change this to another location if you prefer
export LD_LIBRARY_PATH=$WLD/lib
export PKG_CONFIG_PATH=$WLD/lib/pkgconfig/:$WLD/share/pkgconfig/
export PATH=$WLD/bin:$PATH
export ACLOCAL_PATH=$WLD/share/aclocal
export ACLOCAL="aclocal -I $ACLOCAL_PATH"

mkdir -p $WLD/share/aclocal # needed by autotools
Do not set LD_LIBRARY_PATH as your default, it will break things.
Put the above in a script env.sh and source it in the terminal you wish to build the packages.

libdrm

sudo apt-get install xutils-dev libpciaccess-dev
git clone https://anongit.freedesktop.org/git/mesa/drm
cd drm/
source ../env.sh 
./autogen.sh --prefix=$WLD 
make -j128 
make install 

mesa

apt-get install x11proto-dri3-dev:all x11proto-present-dev:all libudev-dev llvm
git clone https://anongit.freedesktop.org/git/mesa/mesa
cd mesa
git checkout mesa-10.1.3
source ../env.sh 
./autogen.sh --prefix=$WLD --enable-egl --enable-opengl  --enable-gles2   --with-egl-platforms=x11,wayland,drm --enable-gbm --enable-shared-glapi   --with-gallium-drivers=r300,r600,swrast,nouveau  --enable-gallium-osmesa --enable-gallium-egl 
 make -j128  
 make install
apply below patch if encountered libdrm/nouveau.h not found error
apply this patch
or just copy
sudo cp /usr/include/libdrm/nouveau/nouveau.h /usr/include/libdrm/

wayland

apt install libffi-dev libexpat-dev libxml2-dev
git clone https://anongit.freedesktop.org/git/wayland/wayland.git
# master head commit 0fa3474be36be5fee98bebb169df68dcf806e3f3
cd wayland
source ../env.sh
./autogen.sh --prefix=$WLD --disable-documentation 
make -j128 
make install

wayland-protocols

git clone https://anongit.freedesktop.org/git/wayland/wayland-protocols.git
cd wayland-protocols
# master, head commit d5ded4ddaf68b161fec23d75204d2153232c3a47
source ../env.sh
./autogen.sh --prefix=$WLD 
make && make install 

libinput

apt install libmtdev-dev libudev-dev libevdev-dev libwacom-dev
git clone https://anongit.freedesktop.org/git/wayland/libinput.git
git checkout 1.7.0 
source ../env.sh
./autogen.sh --prefix=$WLD  --disable-libwacom
make -j128
make install

weston

apt install libegl1-mesa-dev libgles2-mesa-dev libxcursor-dev libcairo2-dev libxcb-composite0-dev libgbm-dev libxkbcommon-dev libjpeg8-dev libpam0g-dev

git clone https://anongit.freedesktop.org/git/wayland/weston
# mater commit 9fe5d5fae9d41bb5f9ec070dbbc0567c738f4141
cd weston
source ../env.sh 
./autogen.sh --prefix=$WLD --disable-setuid-install 
make -j128 
make install 

libxkbcommon

if pkg-config --modversion xkbcommon < 0.5, then compile libxkbcommon

apt-get install libxcb-xkb-dev

git clone https://github.com/xkbcommon/libxkbcommon.git 
cd libxkbcommon
source ../env.sh
./autogen.sh --prefix=$WLD 
make -j128
make install

efl

apt-get install libssl-dev libluajit-5.1-dev libfribidi-dev libgif-dev libtiff-dev libmount-dev libblkid-dev libsndfile1-dev libbullet-dev
apt-get install libgstreamer1*

git clone  https://git.enlightenment.org/core/efl.git/
cd efl
# next commit will require systemd > 209,while ubuntu 14.04 only have 204
git reset --hard cec8a49b51b13670e5adaeb44940f3bece106fb4
source ../env.sh
./autogen.sh --prefix=$WLD --enable-wayland --enable-ecore-wayland --enable-egl --with-opengl=es 
make
make install      

Notes

please confirm that struct wl_egl_window definition in wayland and mesa are same.
struct wl_egl_window {
struct wl_surface *surface;
int width;
int height;
int dx;
int dy;

int attached_width;
int attached_height;

void *private;
void (*resize_callback)(struct wl_egl_window *, void *);
};
otherwise you might got a crash here:
surface->win->surface === 0x3
src/gallium/state_trackers/egl/wayland/native_wayland.c
while try to eglSwapBuffers
wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT],
surface->dx, surface->dy);
invaid arguments errors

Notes

https://wayland.freedesktop.org/building.htmlhttps://wayland.freedesktop.org/efl.html

fixed: embedded-redis: Unable to run on macOS Sonoma

Issue you might see below error while trying to run embedded-redis for your testing on your macOS after you upgrade to Sonoma. java.la...