summaryrefslogtreecommitdiffstats
path: root/firmware/target/hosted/maemo
diff options
context:
space:
mode:
authorThomas Jarosch <tomj@simonv.com>2011-02-08 20:05:25 +0000
committerThomas Jarosch <tomj@simonv.com>2011-02-08 20:05:25 +0000
commit5f037ac015e6d76d030a163753db5ff58cdff49b (patch)
treef5eb7dcdc0e0c3e373227e45061c1d99a14a0819 /firmware/target/hosted/maemo
parent4d129044390a087b6193b6ce63e035b2550b3ce4 (diff)
downloadrockbox-5f037ac015e6d76d030a163753db5ff58cdff49b.tar.gz
rockbox-5f037ac015e6d76d030a163753db5ff58cdff49b.tar.bz2
rockbox-5f037ac015e6d76d030a163753db5ff58cdff49b.zip
Initial maemo platform support
Adds Nokia N900, N810 and N800 support. Features: - Introduce maemo specific platform defines - Play audio in silent mode - Stop playback on incoming calls - Battery level readout - Bluetooth headset support - Save CPU by disabling screen updates if the display is off or the app doesn't have input focus - N900: GStreamer audio backend Kudos to kugel for the code review. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29248 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/hosted/maemo')
-rw-r--r--firmware/target/hosted/maemo/maemo-thread.c220
-rw-r--r--firmware/target/hosted/maemo/maemo-thread.h36
-rw-r--r--firmware/target/hosted/maemo/pcm-gstreamer.c459
3 files changed, 715 insertions, 0 deletions
diff --git a/firmware/target/hosted/maemo/maemo-thread.c b/firmware/target/hosted/maemo/maemo-thread.c
new file mode 100644
index 0000000000..f655ed597e
--- /dev/null
+++ b/firmware/target/hosted/maemo/maemo-thread.c
@@ -0,0 +1,220 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 by Thomas Jarosch
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <libhal.h>
+#include <libosso.h>
+#include <SDL_thread.h>
+
+#include "config.h"
+#include "system.h"
+#include "kernel.h"
+#include "thread.h"
+#include "power.h"
+#include "debug.h"
+#include "button.h"
+
+/* Battery status information */
+#define BME_UDI "/org/freedesktop/Hal/devices/bme"
+#define BATTERY_PERCENTAGE "battery.charge_level.percentage"
+#define BATTER_REMAINING_TIME "battery.remaining_time"
+
+/* Bluetooth headset support */
+#define BT_HEADSET_UDI "/org/freedesktop/Hal/devices/computer_logicaldev_input_1"
+
+GMainLoop *maemo_main_loop = NULL;
+osso_context_t *maemo_osso_ctx = NULL;
+
+volatile int maemo_display_on = 1;
+volatile int maemo_battery_level = 0;
+volatile int maemo_remaining_time_sec = 0;
+
+extern void send_battery_level_event(void);
+extern int last_sent_battery_level;
+extern int battery_percent;
+
+void display_status_callback(osso_display_state_t state, gpointer data)
+{
+ (void)data;
+
+ if (state == OSSO_DISPLAY_OFF)
+ maemo_display_on = 0;
+ else
+ maemo_display_on = 1;
+}
+
+
+void get_battery_values(LibHalContext *ctx)
+{
+ /* Get initial battery percentage and remaining time */
+ maemo_battery_level = libhal_device_get_property_int(
+ ctx, BME_UDI,
+ BATTERY_PERCENTAGE, NULL);
+
+ maemo_remaining_time_sec = libhal_device_get_property_int(
+ ctx, BME_UDI,
+ BATTER_REMAINING_TIME, NULL);
+
+ DEBUGF("[maemo] Battery percentage: %d, remaining_time_sec: %d\n", maemo_battery_level, maemo_remaining_time_sec);
+}
+
+static void on_battery_changed (LibHalContext *ctx,
+ const char *udi,
+ const char *key,
+ dbus_bool_t is_removed,
+ dbus_bool_t is_added)
+{
+ (void)is_removed;
+ (void)is_added;
+
+ if (!g_str_equal (udi, BME_UDI))
+ return;
+
+ if (!g_str_equal (key, BATTERY_PERCENTAGE) && !g_str_equal (key, BATTER_REMAINING_TIME))
+ return;
+
+ get_battery_values(ctx);
+}
+
+static void on_bt_button_pressed(LibHalContext *ctx,
+ const char *udi,
+ const char *condition_name,
+ const char *condition_detail)
+{
+ (void)ctx;
+
+ if (!g_str_equal (udi, BT_HEADSET_UDI) || !g_str_equal(condition_name, "ButtonPressed"))
+ return;
+
+ sim_enter_irq_handler();
+
+ if (g_str_equal(condition_detail, "play-cd") || g_str_equal(condition_detail, "pause-cd"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_PLAYPAUSE, 0);
+ else if (g_str_equal(condition_detail, "stop-cd"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_STOP, 0);
+ else if (g_str_equal(condition_detail, "next-song"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_NEXT, 0);
+ else if (g_str_equal(condition_detail, "previous-song"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_PREV, 0);
+ else if (g_str_equal(condition_detail, "fast-forward"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_FFWD, 0);
+ else if (g_str_equal(condition_detail, "rewind"))
+ queue_post(&button_queue, BUTTON_MULTIMEDIA_REW, 0);
+
+ sim_exit_irq_handler();
+}
+
+int maemo_thread_func (void *wait_for_osso_startup)
+{
+ maemo_main_loop = g_main_loop_new (NULL, FALSE);
+
+ /* Register display callback */
+ maemo_osso_ctx = osso_initialize ("rockbox", "666", FALSE, NULL);
+ osso_hw_set_display_event_cb(maemo_osso_ctx, display_status_callback, NULL);
+
+ /* Register battery status callback */
+ LibHalContext *hal_ctx;
+ hal_ctx = libhal_ctx_new();
+
+ DBusConnection *system_bus = (DBusConnection*)osso_get_sys_dbus_connection(maemo_osso_ctx);
+ libhal_ctx_set_dbus_connection(hal_ctx, system_bus);
+
+ libhal_ctx_init(hal_ctx, NULL);
+ libhal_ctx_set_device_property_modified (hal_ctx, on_battery_changed);
+ libhal_device_add_property_watch (hal_ctx, BME_UDI, NULL);
+
+ /* Work around libhal API issue: We need to add a property watch
+ to get the condition change callback working */
+ libhal_device_add_property_watch (hal_ctx, BT_HEADSET_UDI, NULL);
+ libhal_ctx_set_device_condition(hal_ctx, on_bt_button_pressed);
+
+ get_battery_values(hal_ctx);
+
+ /* let system_init proceed */
+ SDL_SemPost((SDL_sem *)wait_for_osso_startup);
+
+ g_main_loop_run (maemo_main_loop);
+
+ /* Cleanup */
+ osso_deinitialize (maemo_osso_ctx);
+ libhal_device_remove_property_watch (hal_ctx, BT_HEADSET_UDI, NULL);
+ libhal_device_remove_property_watch (hal_ctx, BME_UDI, NULL);
+ libhal_ctx_shutdown (hal_ctx, NULL);
+ libhal_ctx_free(hal_ctx);
+
+ return 0;
+}
+
+/** Rockbox battery related functions */
+void battery_status_update(void)
+{
+ battery_percent = maemo_battery_level;
+ send_battery_level_event();
+}
+
+/* Returns true if any power input is connected - charging-capable
+ * or not. */
+bool power_input_present(void)
+{
+ return false;
+}
+
+unsigned battery_voltage(void)
+{
+ return 0;
+}
+
+/* Returns battery level in percent */
+int battery_level(void)
+{
+ battery_status_update();
+ return maemo_battery_level;
+}
+
+/* Return remaining battery time in minutes */
+int battery_time(void)
+{
+ battery_status_update();
+ return maemo_remaining_time_sec / 60;
+}
+
+bool battery_level_safe(void)
+{
+ return battery_level() >= 5;
+}
+
+/** Rockbox stubs */
+void set_poweroff_timeout(int timeout)
+{
+ (void)timeout;
+}
+
+void reset_poweroff_timer(void)
+{
+}
+
+void shutdown_hw(void)
+{
+}
+
+void cancel_shutdown(void)
+{
+}
diff --git a/firmware/target/hosted/maemo/maemo-thread.h b/firmware/target/hosted/maemo/maemo-thread.h
new file mode 100644
index 0000000000..a0996b4945
--- /dev/null
+++ b/firmware/target/hosted/maemo/maemo-thread.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 by Thomas Jarosch
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __MAEMO_THREAD_H__
+#define __MAEMO_THREAD_H__
+
+#include <glib.h>
+#include <libosso.h>
+
+extern osso_context_t *maemo_osso_ctx;
+extern GMainLoop *maemo_main_loop;
+
+extern volatile int maemo_display_on;
+extern volatile int maemo_has_input_focus;
+
+int maemo_thread_func(void *unused);
+void pcm_shutdown_gstreamer(void);
+
+#endif
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c
new file mode 100644
index 0000000000..e3e40f0619
--- /dev/null
+++ b/firmware/target/hosted/maemo/pcm-gstreamer.c
@@ -0,0 +1,459 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 by Thomas Jarosch
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include "autoconf.h"
+
+#include <stdbool.h>
+#include "config.h"
+#include "debug.h"
+#include "sound.h"
+#include "audiohw.h"
+#include "system.h"
+#include "settings.h"
+#include "debug.h"
+
+#include "playback.h"
+#include "kernel.h"
+
+#include <SDL.h>
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/app/gstappsrc.h>
+#include <linux/types.h>
+
+/* Maemo5: N900 specific libplayback support */
+#include <libplayback/playback.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include "maemo-thread.h"
+
+#ifdef HAVE_RECORDING
+#include "audiohw.h"
+#ifdef HAVE_SPDIF_IN
+#include "spdif.h"
+#endif
+#endif
+
+#include "pcm.h"
+#include "pcm_sampr.h"
+
+/*#define LOGF_ENABLE*/
+#include "logf.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+extern bool debug_audio;
+#endif
+
+#if CONFIG_CODEC == SWCODEC
+
+/* Declarations for libplayblack */
+pb_playback_t *playback = NULL;
+void playback_state_req_handler(pb_playback_t *pb,
+ enum pb_state_e req_state,
+ pb_req_t *ext_req,
+ void *data);
+void playback_state_req_callback(pb_playback_t *pb,
+ enum pb_state_e granted_state,
+ const char *reason,
+ pb_req_t *req,
+ void *data);
+bool playback_granted = false;
+
+/* Gstreamer related vars */
+GstCaps *gst_audio_caps = NULL;
+GstElement *gst_pipeline = NULL;
+GstElement *gst_appsrc = NULL;
+GstElement *gst_volume = NULL;
+GstElement *gst_pulsesink = NULL;
+GstBus *gst_bus = NULL;
+static int bus_watch_id = 0;
+GMainLoop *pcm_loop = NULL;
+
+static __u8* pcm_data = NULL;
+static size_t pcm_data_size = 0;
+
+static int inside_feed_data = 0;
+
+void pcm_play_lock(void)
+{
+}
+
+void pcm_play_unlock(void)
+{
+}
+
+void pcm_dma_apply_settings(void)
+{
+}
+
+void pcm_play_dma_start(const void *addr, size_t size)
+{
+ pcm_data = (__u8 *) addr;
+ pcm_data_size = size;
+
+ if (playback_granted)
+ {
+ /* Start playing now */
+ if (!inside_feed_data)
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
+ else
+ DEBUGF("ERROR: dma_start called while inside feed_data\n");
+ } else
+ {
+ /* N900: Request change to playing state */
+ pb_playback_req_state (playback,
+ PB_STATE_PLAY,
+ playback_state_req_callback,
+ NULL);
+ }
+}
+
+void pcm_play_dma_stop(void)
+{
+ if (inside_feed_data)
+ g_signal_emit_by_name (gst_appsrc, "end-of-stream", NULL);
+ else
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
+}
+
+void pcm_play_dma_pause(bool pause)
+{
+ if (inside_feed_data)
+ {
+ if (pause)
+ g_signal_emit_by_name (gst_appsrc, "end-of-stream", NULL);
+ else
+ DEBUGF("ERROR: Called dma_pause(0) while inside feed_data\n");
+ } else
+ {
+ if (pause)
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
+ else
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
+ }
+}
+
+size_t pcm_get_bytes_waiting(void)
+{
+ return pcm_data_size;
+}
+
+static void feed_data(GstElement * appsrc, guint size_hint, void *unused)
+{
+ (void)size_hint;
+ (void)unused;
+
+ /* Make sure we don't trigger a gst_element_set_state() call
+ from inside gstreamer's stream thread as it will deadlock */
+ inside_feed_data = 1;
+
+ pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
+
+ if (pcm_data_size != 0)
+ {
+ GstBuffer *buffer = gst_buffer_new ();
+ GstFlowReturn ret;
+
+ GST_BUFFER_DATA (buffer) = pcm_data;
+ GST_BUFFER_SIZE (buffer) = pcm_data_size;
+
+ g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
+ gst_buffer_unref (buffer);
+
+ if (ret != 0)
+ DEBUGF("push-buffer error result: %d\n", ret);
+ } else
+ {
+ DEBUGF("feed_data: No Data.\n");
+ g_signal_emit_by_name (appsrc, "end-of-stream", NULL);
+ }
+
+ inside_feed_data = 0;
+}
+
+const void * pcm_play_dma_get_peak_buffer(int *count)
+{
+ uintptr_t addr = (uintptr_t)pcm_data;
+ *count = pcm_data_size / 4;
+ return (void *)((addr + 2) & ~3);
+}
+
+
+static gboolean
+gst_bus_message (GstBus * bus, GstMessage * message, void *unused)
+{
+ (void)bus;
+ (void)unused;
+
+ DEBUGF(" [gst] got BUS message %s\n",
+ gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
+
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err;
+ gchar *debug;
+ gst_message_parse_error (message, &err, &debug);
+
+ DEBUGF("[gst] Received error: Src: %s, msg: %s\n", GST_MESSAGE_SRC_NAME(message), err->message);
+
+ g_error_free (err);
+ g_free (debug);
+ }
+
+ g_main_loop_quit (pcm_loop);
+ break;
+ case GST_MESSAGE_EOS:
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
+ break;
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState old_state, new_state;
+
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+ DEBUGF("[gst] Element %s changed state from %s to %s.\n",
+ GST_MESSAGE_SRC_NAME(message),
+ gst_element_state_get_name (old_state),
+ gst_element_state_get_name (new_state));
+ break;
+ }
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+void maemo_configure_appsrc(void)
+{
+ /* Block push-buffer until there is enough room */
+ g_object_set (G_OBJECT(gst_appsrc), "block", TRUE, NULL);
+
+ g_object_set(G_OBJECT(gst_appsrc), "format", GST_FORMAT_BYTES, NULL);
+
+ gst_audio_caps = gst_caps_new_simple("audio/x-raw-int", "width", G_TYPE_INT, (gint)16, "depth", G_TYPE_INT, (gint)16, "channels" ,G_TYPE_INT, (gint)2,
+ "signed",G_TYPE_BOOLEAN,1,
+ "rate",G_TYPE_INT,44100,"endianness",G_TYPE_INT,(gint)1234,NULL);
+
+ g_object_set (G_OBJECT(gst_appsrc), "caps", gst_audio_caps, NULL);
+
+ gst_app_src_set_stream_type(GST_APP_SRC(gst_appsrc),
+ GST_APP_STREAM_TYPE_STREAM);
+
+ /* configure the appsrc, we will push data into the appsrc from the
+ * mainloop. */
+ g_signal_connect (gst_appsrc, "need-data", G_CALLBACK (feed_data), NULL);
+}
+
+/* Init libplayback: Grant access rights to
+ play audio while the phone is in silent mode */
+void maemo_init_libplayback(void)
+{
+ DBusConnection *session_bus_raw = (DBusConnection*)osso_get_dbus_connection(maemo_osso_ctx);
+
+ playback = pb_playback_new_2(session_bus_raw,
+ PB_CLASS_MEDIA,
+ PB_FLAG_AUDIO,
+ PB_STATE_STOP,
+ playback_state_req_handler,
+ NULL);
+
+ pb_playback_set_stream(playback, "Playback Stream");
+}
+
+/**
+ * Gets called by the policy framework if an important
+ * event arrives: Incoming calls etc.
+ */
+void maemo_tell_rockbox_to_stop_audio(void)
+{
+ sim_enter_irq_handler();
+ queue_broadcast(SYS_CALL_INCOMING, 0);
+ sim_exit_irq_handler();
+
+ osso_system_note_infoprint(maemo_osso_ctx, "Stopping rockbox playback", NULL);
+}
+
+void playback_state_req_handler(pb_playback_t *pb,
+ enum pb_state_e req_state,
+ pb_req_t *ext_req,
+ void *data)
+{
+ (void)pb;
+ (void)ext_req;
+ (void)data;
+
+ DEBUGF("External state change request: state: %s, data: %p\n",
+ pb_state_to_string(req_state), data);
+
+ if (req_state == PB_STATE_STOP && playback_granted)
+ {
+ DEBUGF("Stopping playback, might be an incoming call\n");
+
+ playback_granted = false;
+ maemo_tell_rockbox_to_stop_audio();
+ }
+}
+
+/**
+ * Callback for our own state change request.
+ */
+void playback_state_req_callback(pb_playback_t *pb, enum pb_state_e granted_state, const char *reason, pb_req_t *req, void *data)
+{
+ (void)data;
+ (void)reason;
+
+ DEBUGF("State request callback: granted_state: %s, reason: %s\n",
+ pb_state_to_string(granted_state), reason);
+
+ /* We are allowed to play audio */
+ if (granted_state == PB_STATE_PLAY)
+ {
+ DEBUGF("Playback granted. Start playing...\n");
+ playback_granted = true;
+ if (!inside_feed_data)
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_PLAYING);
+ } else
+ {
+ DEBUGF("Can't start playing. Throwing away play request\n");
+
+ playback_granted = false;
+ maemo_tell_rockbox_to_stop_audio();
+ }
+
+ pb_playback_req_completed(pb, req);
+}
+
+void pcm_play_dma_init(void)
+{
+ maemo_init_libplayback();
+
+ GMainContext *ctx = g_main_loop_get_context(maemo_main_loop);
+ pcm_loop = g_main_loop_new (ctx, true);
+
+ gst_init (NULL, NULL);
+
+ gst_pipeline = gst_pipeline_new ("rockbox");
+
+ gst_appsrc = gst_element_factory_make ("appsrc", NULL);
+ gst_volume = gst_element_factory_make ("volume", NULL);
+ gst_pulsesink = gst_element_factory_make ("pulsesink", NULL);
+
+ /* Connect elements */
+ gst_bin_add_many (GST_BIN (gst_pipeline),
+ gst_appsrc, gst_volume, gst_pulsesink, NULL);
+ gst_element_link_many (gst_appsrc, gst_volume, gst_pulsesink, NULL);
+
+ /* Connect to gstreamer bus of the pipeline */
+ gst_bus = gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline));
+ bus_watch_id = gst_bus_add_watch (gst_bus, (GstBusFunc) gst_bus_message, NULL);
+
+ maemo_configure_appsrc();
+}
+
+void pcm_shutdown_gstreamer(void)
+{
+ /* Try to stop playing */
+ gst_element_set_state (GST_ELEMENT(gst_pipeline), GST_STATE_NULL);
+
+ /* Make sure we are really stopped. This should return almost instantly,
+ so we wait up to ten seconds and just continue otherwise */
+ gst_element_get_state (GST_ELEMENT(gst_pipeline), NULL, NULL, GST_SECOND * 10);
+
+ g_source_remove (bus_watch_id);
+ g_object_unref(gst_bus);
+ gst_bus = NULL;
+
+ gst_object_unref (gst_pipeline);
+ gst_pipeline = NULL;
+
+ /* Shutdown libplayback and gstreamer */
+ pb_playback_destroy (playback);
+ gst_deinit();
+
+ g_main_loop_quit(pcm_loop);
+ g_main_loop_unref (pcm_loop);
+}
+
+void pcm_postinit(void)
+{
+}
+
+void pcm_set_mixer_volume(int volume)
+{
+ /* gstreamer volume range is from 0.00 to 1.00 */
+ gdouble gst_vol = (gdouble)(volume - VOLUME_MIN) / (gdouble)VOLUME_RANGE;
+
+ g_object_set (G_OBJECT(gst_volume), "volume", gst_vol, NULL);
+}
+
+
+#ifdef HAVE_RECORDING
+void pcm_rec_lock(void)
+{
+}
+
+void pcm_rec_unlock(void)
+{
+}
+
+void pcm_rec_dma_init(void)
+{
+}
+
+void pcm_rec_dma_close(void)
+{
+}
+
+void pcm_rec_dma_start(void *start, size_t size)
+{
+ (void)start;
+ (void)size;
+}
+
+void pcm_rec_dma_stop(void)
+{
+}
+
+const void * pcm_rec_dma_get_peak_buffer(void)
+{
+ return NULL;
+}
+
+void audiohw_set_recvol(int left, int right, int type)
+{
+ (void)left;
+ (void)right;
+ (void)type;
+}
+
+#ifdef HAVE_SPDIF_IN
+unsigned long spdif_measure_frequency(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* HAVE_RECORDING */
+
+#endif /* CONFIG_CODEC == SWCODEC */