blob: b226100318d05e330866f949ece9ed505fc73a3d [file] [log] [blame]
// 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);
}