| // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <assert.h> |
| #include <dirent.h> |
| #include <linux/input.h> |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <cras_client.h> |
| |
| #include "audio_utils.h" |
| |
| static const size_t MAX_IONODES = 20; |
| static int aud_verbose = 0; |
| |
| /* These variables are shared with the report thread. */ |
| static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
| static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; |
| static int hdmi_audio_available; |
| |
| static struct cras_client *client; |
| static enum { |
| CLIENT_INIT, |
| CLIENT_CREATED, |
| CLIENT_CONNECTED, |
| CLIENT_THREAD_RUN, |
| CLIENT_READY, |
| } client_status; |
| |
| static int connect_to_server() |
| { |
| int err = 0; |
| switch (client_status) { |
| case CLIENT_INIT: |
| err = cras_client_create(&client); |
| if (err) { |
| printf("Audio: failed to create client\n"); |
| return err; |
| } |
| client_status = CLIENT_CREATED; |
| // fallthrough |
| case CLIENT_CREATED: |
| err = cras_client_connect(client); |
| if (err) { |
| printf("Audio: failed to connect to server\n"); |
| return err; |
| } |
| client_status = CLIENT_CONNECTED; |
| // fallthrough |
| case CLIENT_CONNECTED: |
| err = cras_client_run_thread(client); |
| if (err) { |
| printf("Audio: failed to run client thread\n"); |
| return err; |
| } |
| client_status = CLIENT_THREAD_RUN; |
| // fallthrough |
| case CLIENT_THREAD_RUN: |
| err = cras_client_connected_wait(client); |
| if (err) { |
| printf("Audio: failed to wait connected.\n"); |
| return err; |
| } |
| client_status = CLIENT_READY; |
| printf("Audio: client ready\n"); |
| // fallthrough |
| case CLIENT_READY: |
| default: |
| return 0; |
| } |
| } |
| |
| /* Sends the availability message to server. Returns 0 if successful, -1 |
| * otherwise. */ |
| static int send_state_to_server(int available) |
| { |
| size_t num_devs = 0; |
| size_t num_nodes = MAX_IONODES; |
| struct cras_ionode_info nodes[MAX_IONODES]; |
| int rc, i; |
| |
| if (connect_to_server() != 0) |
| return -1; |
| |
| rc = cras_client_get_output_devices(client, NULL, nodes, &num_devs, |
| &num_nodes); |
| if (rc < 0) { |
| printf("Audio: cannot get output nodes\n"); |
| return -1; |
| } |
| |
| for (i = 0; i < num_nodes; i++) { |
| if (!strcmp(nodes[i].name, "IEC958")) { |
| cras_node_id_t node_id = cras_make_node_id(nodes[i].iodev_idx, |
| nodes[i].ionode_idx); |
| cras_client_set_node_attr(client, node_id, IONODE_ATTR_PLUGGED, |
| available); |
| return 0; |
| } |
| } |
| |
| printf("Audio: IEC959 node is not found\n"); |
| return -1; |
| } |
| |
| /* A thread which reports the hdmi audio state to the server. */ |
| static void *report_thread(void *arg) |
| { |
| /* The state that has been reported to the server successfully. */ |
| int reported = 0; |
| int available; |
| |
| while (1) |
| { |
| /* Wait until the availablity changes */ |
| pthread_mutex_lock(&mutex); |
| while (hdmi_audio_available == reported) |
| pthread_cond_wait(&cond, &mutex); |
| available = hdmi_audio_available; |
| pthread_mutex_unlock(&mutex); |
| |
| /* Report the new state */ |
| if (send_state_to_server(available) == 0) { |
| reported = available; |
| } else { |
| /* If we failed to connect to the server, sleep for five seconds and |
| * retry. */ |
| sleep(5); |
| } |
| } |
| } |
| |
| int audio_init(int verbose) |
| { |
| pthread_t thread; |
| aud_verbose = verbose; |
| if (aud_verbose) printf("Audio: init\n"); |
| pthread_create(&thread, NULL, report_thread, NULL); |
| return 0; |
| } |
| |
| void audio_to_hdmi(int available) |
| { |
| if (available == hdmi_audio_available) |
| return; |
| if (aud_verbose) printf("Audio: Set HDMI audio output to %s\n", |
| available ? "Available" : "Unavailable"); |
| pthread_mutex_lock(&mutex); |
| hdmi_audio_available = available; |
| pthread_cond_signal(&cond); |
| pthread_mutex_unlock(&mutex); |
| } |