#!/bin/sh
#
# Plays and records media clips (currently only audio clips).
#
# Example usage:
#
# Play clip specified by root.MediaClip.M2:
#   mediaclip.cgi?action=play&clip=2
#
# Play /tmp/mysound.au:
#   mediaclip.cgi?action=play&location=/tmp/mysound.au
#
# Wait 5 seconds and then record new clip during 10 seconds:
#   mediaclip.cgi?action=record&wait=5&duration=10
#
# Parameter 'generate_header' may be used to skip response header.
#

# Error output to console
#exec 2> /dev/console

. /usr/html/axis-cgi/lib/functions.sh

AUDIO_FILE_PATH=/etc/audioclips
PARHANDCLIENT="parhandclient --nocgi"
DBUS_SEND_AUDIO="dbus-send --system --dest=com.axis.Streamer.Audio --print-reply --type=method_call /com/axis/Streamer/Audio"
RM="rm -f"

ENCODERTYPE=g711
DEFAULT_SAMPLERATE=16000

# CGI compliant by default
CGI_HDGEN=$(__qs_getparam generate_header) || CGI_HDGEN=yes

printout() {
	if [ "$CGI_HDGEN" = no ]; then
		echo "$2"
	else
		__cgi_errhd $1 "$2"
		CGI_HDGEN=no # To prevent duplicated header.
	fi
}

ok() {
	printout 200 "OK\r\n$1=$2"
}

error() {
	printout 400 "$1"
	exit 1
}

sane_location() {
	LOCATION=${LOCATION##file://}
	if [ "${LOCATION##http://}" = "$LOCATION" ]; then
		[ "${LOCATION##$AUDIO_FILE_PATH/}" != "$LOCATION" ] ||
			return 1
		RET=$(echo "$LOCATION" | grep -v '\.\.') ||
			return 2
	fi
	return 0
}

ACTION=$(__qs_getparam action) || ACTION=
[ "$ACTION" ] || error "Missing parameter: action required."

case "$ACTION" in
	play)
		CLIP=$(__qs_getparam clip) || CLIP=
		[ "$CLIP" ] || error "Missing parameter: clip required."
		LOCATION=$($PARHANDCLIENT get MediaClip.M$CLIP.Location - RAW) ||
			error "Clip number [$CLIP] not found."
#		[ -r "$LOCATION" ] || error "Clip location [$LOCATION] not found."
		RET=$($DBUS_SEND_AUDIO com.axis.Streamer.Audio.PlayClip 			string:"location=$LOCATION") ||
			error "Failed to play clip $CLIP."
		ok "playing" $CLIP
		;;
	record)
		SAMPLERATE=$(__qs_getparam samplerate) ||
			SAMPLERATE=$DEFAULT_SAMPLERATE
		case $SAMPLERATE in
			$DEFAULT_SAMPLERATE|8000)
				;;
			*)
				error "Samplerate value not supported."
		esac
		MEDIATYPE=$(__qs_getparam media) && [ "$MEDIATYPE" ] ||
			error "Missing parameter: media required."
		[ "$MEDIATYPE" = audio ] ||
			error "Unknown media type. Supported media types: audio"
		DURATION=$(__qs_getparam duration) || DURATION=10
		WAIT=$(__qs_getparam wait) || WAIT=0
		# Validate digits only with 'expr' anchored pattern match.
		# Number of digits found by 'expr' must be equal to string length.
		[ $(expr $DURATION : '[0-9]\+') -eq ${#DURATION} ] ||
			error "Parameter duration must be an integer."
		[ $(expr $WAIT : '[0-9]\+') -eq ${#WAIT} ] ||
			error "Parameter wait must be an integer."
		CLIP=$($PARHANDCLIENT addgroup MediaClip mediaclip) ||
			error "Failed to add clip to parameters: $CLIP."
		LOCATION=$AUDIO_FILE_PATH/$CLIP.au
		RET=$($PARHANDCLIENT set $CLIP.Location $LOCATION) ||
			error "Failed to set clip location: $RET."
		NAME=$(__qs_getparam name) && [ "$NAME" ] || NAME="Clip $CLIP"
		RET=$($PARHANDCLIENT set $CLIP.Name "$NAME") ||
			error "Failed to set clip name: $RET."
		STATUSLED=$(__qs_getparam statusled) && [ "$STATUSLED" ] || STATUSLED=yes
		[ "$STATUSLED" = no ] ||
			set_led statusled assistant_yellow
		[ $WAIT -le 0 ] || sleep $WAIT
		RET=$($DBUS_SEND_AUDIO com.axis.Streamer.Audio.RecordClip 			string:"location=$LOCATION&duration=$DURATION&audio=1&audiocodec=$ENCODERTYPE&audiosamplerate=$SAMPLERATE") ||
			error "Failed to record clip $CLIP."
		ok "recording" $CLIP
		[ "$STATUSLED" = no ] ||
			set_led statusled assistant_red
		[ $DURATION -le 0 ] || sleep $DURATION
		if [ "$STATUSLED" != no ]; then
			set_led statusled normal
		fi
		;;
	update)
		CLIP=$(__qs_getparam clip) && [ "$CLIP" ] ||
			error "Missing parameter: clip required."
		NAME=$(__qs_getparam name) || NAME=
		if [ "$NAME" ]; then
			$PARHANDCLIENT set MediaClip.M$CLIP.Name "$NAME" ||
				error "Failed to update clip $CLIP."
		fi
		ok "updated" $CLIP
		;;
	remove)
		CLIP=$(__qs_getparam clip) && [ "$CLIP" ] ||
			error "Missing parameter: clip required."
		LOCATION=$($PARHANDCLIENT get MediaClip.M$CLIP.Location - RAW) ||
			error "Clip number [$CLIP] not found."
		$PARHANDCLIENT deletegroup MediaClip.M$CLIP ||
			error "Failed to remove clip parameter M$CLIP."
		sane_location ||
			logger "Clip location not valid, ignoring removal: $LOCATION"
		[ "${LOCATION##http://}" != "$LOCATION" ] || $RM "$LOCATION" ||
			logger "Failed to remove clip location $LOCATION: $?."
		ok "removed" $CLIP
		;;
	download)
		CLIP=$(__qs_getparam clip) && [ "$CLIP" ] ||
			error "Missing parameter: clip required."
		LOCATION=$($PARHANDCLIENT get MediaClip.M$CLIP.Location - RAW) ||
			error "Clip number [$CLIP] not found."
		sane_location || error "Clip location not valid."
		[ -r "$LOCATION" ] || error "Clip location [$LOCATION] not found."
		if [ ${LOCATION##*.} = au ]; then
			mimetype="audio/basic"
		else
			mimetype="audio/x-wav"
		fi
		con_dis="$mimetype\r\nContent-Disposition: attachment; filename=\"${LOCATION##*/}\""
		__cgi_hdgen yes "$con_dis"
		cat "$LOCATION" || exit 1
		;;
	upload)
		MEDIATYPE=$(__qs_getparam media) && [ "$MEDIATYPE" ] ||
			error "Missing parameter: media required."
		[ "$MEDIATYPE" = audio ] ||
			error "Unknown media type. Supported media types: audio"
		LOCATION=$(file_upload -s $CONTENT_LENGTH -n 65536 -a) ||
			error "Failed to upload clip: $?."
		chgrp streamer "$LOCATION" && chmod 640 "$LOCATION" ||
			error "Failed to change owner and/or permissions" 			      "on '$LOCATION'."
		CLIP=$($PARHANDCLIENT addgroup MediaClip mediaclip) ||
			error "Failed to add clip to parameters: $CLIP."
		RET=$($PARHANDCLIENT set $CLIP.Location "$LOCATION") ||
			error "Failed to set clip location: $RET."
		NAME=$(__qs_getparam name) && [ "$NAME" ] || NAME="Clip $CLIP"
		RET=$($PARHANDCLIENT set $CLIP.Name "$NAME") ||
			error "Failed to set clip name: $RET."
		ok "uploaded" $CLIP
		;;
	*)
		error "Unknown action: $ACTION."
	;;
esac
exit 0
