~mil/sxmo-tickets#544: 
Local voicemail

Please ignore VVM. This is not related to VVM.

On incoming call, SXMO shows these items: Pickup, Hangup, Ignore.

I suggest to add a new item: Voicemail

  1. Incoming call.
  2. User activates Voicemail.
  3. SXMO starts the call.
  4. SXMO starts audio recording.
  5. SXMO plays "I'm out of town" audio.
  6. SXMO ends call after 60 seconds (default time period).

This is easy and simple to implement. No popular device offers this feature.

New incoming call: Pickup, Hangup, Voicemail, Ignore

Status
REPORTED
Submitter
~kohn
Assigned to
No-one
Submitted
2 months ago
Updated
2 months ago
Labels
feature

~kohn referenced this from #541 2 months ago

~phartman 2 months ago

This would be a great script for the userscripts. Shouldn't be too hard to implement with the current hook structure, right? I'd be open to adding hooks if needed for the script, but need the POC code for that!

~kohn 2 months ago

How can this be activated or called as a userscript? I figure this should be added to the Incall menu that appears upon an incoming call.

What's POC?

By the way, once implemented in SXMO, this feature will be one of a kind as no client-driven platform provides this, except cassette telephone devices from the 80's/90's.

~phartman 2 months ago

The place to check would be sxmo_modem.sh in the checkforincomingcall() function. A quick glance suggests, while you might be able to get away with shoving the logic in the sxmo_hook_ring.sh function, e.g.,

if [ "$SXMO_VOICEMAIL_MODE" ]; then VOICECALLID="$( mmcli -m any --voice-list-calls -a | grep -Eo '[0-9]+ incoming (ringing-in)' | grep -Eo '[0-9]+' )"

your logic here

fi

I guess it depends on how you want to go about implementing it. (POC = Proof of Concept, which in sxmo terms would just be a patch submitted to the list :D)

Sounds like a fun idea

On Mon, Jan 02, 2023 at 09:31:47PM +0000, ~kohn wrote:

How can this be activated or called as a userscript? I figure this should be added to the Incall menu that appears upon an incoming call.

What's POC?

By the way, once implemented in SXMO, this feature will be one of a kind as no client-driven platform provides this, except cassette telephone devices from the 80's/90's.

-- View on the web: https://todo.sr.ht/~mil/sxmo-tickets/544#event-219667

-- sic dicit magister P https://phartman.sites.luc.edu/ GPG keyID 0xE0DBD3D6 (CAE6 3A6F 755F 7BC3 36CA 330D B3E6 39C6 E0DB D3D6)

~phartman referenced this from #544 2 months ago

~kohn 2 months ago

On Mon, 02 Jan 2023 21:47:18 +0000 "~phartman" outgoing@sr.ht wrote:

The place to check would be sxmo_modem.sh in the checkforincomingcall() function. A quick glance suggests, while you might be able to get away with shoving the logic in the sxmo_hook_ring.sh function, e.g.,

if [ "$SXMO_VOICEMAIL_MODE" ]; then VOICECALLID="$( mmcli -m any --voice-list-calls -a | grep -Eo '[0-9]+ incoming (ringing-in)' | grep -Eo '[0-9]+' )"

your logic here

Thank you, Peter, for the reference and code to start with. I'll work on this in the morning.

Answer & Mute & Capture sound Pipe an audio file to caller ("I'm out of town") Hangup after 60 seconds

fi

I guess it depends on how you want to go about implementing it. (POC = Proof of Concept, which in sxmo terms would just be a patch submitted to the list :D)

Sounds like a fun idea

~phartman referenced this from #544 2 months ago

~phartman 2 months ago

btw I just saw this hit the biktorgj firmware list:

https://github.com/the-modem-distro/pinephone_modem_sdk/issues/184

Must be something in the air, lol.

On Tue, Jan 03, 2023 at 12:44:33AM +0000, ~kohn wrote:

On Mon, 02 Jan 2023 21:47:18 +0000 "~phartman" outgoing@sr.ht wrote:

The place to check would be sxmo_modem.sh in the checkforincomingcall() function. A quick glance suggests, while you might be able to get away with shoving the logic in the sxmo_hook_ring.sh function, e.g.,

if [ "$SXMO_VOICEMAIL_MODE" ]; then VOICECALLID="$( mmcli -m any --voice-list-calls -a | grep -Eo '[0-9]+ incoming (ringing-in)' | grep -Eo '[0-9]+' )"

your logic here

Thank you, Peter, for the reference and code to start with. I'll work on this in the morning.

Answer & Mute & Capture sound Pipe an audio file to caller ("I'm out of town") Hangup after 60 seconds

fi

I guess it depends on how you want to go about implementing it. (POC = Proof of Concept, which in sxmo terms would just be a patch submitted to the list :D)

Sounds like a fun idea

-- View on the web: https://todo.sr.ht/~mil/sxmo-tickets/544#event-219681

-- sic dicit magister P https://phartman.sites.luc.edu/ GPG keyID 0xE0DBD3D6 (CAE6 3A6F 755F 7BC3 36CA 330D B3E6 39C6 E0DB D3D6)

~kohn 2 months ago*

pinephone_modem_sdk

  1. Incoming call.
  2. User activates Voicemail.
  3. SXMO mutes audio.
  4. SXMO switches to speaker audio mode.
  5. SXMO starts the call.
  6. SXMO captures sound.
  7. SXMO plays audio "I'm out of town".
  8. After 60 seconds (default time period)...
  9. SXMO plays audio "Voicemail time is over. This voicemail is powered by postmarketOS. Goodbye." <- Marketing
  10. SXMO ends call.

other firmware

  1. Incoming call.
  2. User activates Voicemail.
  3. SXMO switches to Speaker audio mode.
  4. SXMO records sound.
  5. SXMO starts the call.
  6. SXMO plays audio "I'm out of town".
  7. SXMO mutes audio.
  8. After 60 seconds (default time period)...
  9. SXMO plays audio "Voicemail time is over. This voicemail is powered by postmarketOS. Goodbye." <- Marketing
  10. SXMO ends call.

~kohn 2 months ago*

I'm looking at sxmo_modemcall.sh to make a manual mode. This work is based on the fuction incall_menu()

Once I make the manual mode operational, I'll continue with automated mode.

This is how I want it to look like, but I will make it simple for start and add menu later.

It is challenging. I need help with sxmo_hook_answerphone.sh

Here's is what I've done:

File: sxmo_modemcall.sh

#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors

# include common definitions
# shellcheck source=configs/default_hooks/sxmo_hook_icons.sh
. sxmo_hook_icons.sh
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh

# We use this directory to store states, so it must exist
mkdir -p "$XDG_RUNTIME_DIR/sxmo_calls"

set -e

vid_to_number() {
	mmcli -m any -o "$1" -K | \
		grep call.properties.number | \
		cut -d ':' -f2 | \
		tr -d  ' '
}

log_event() {
	EVT_HANDLE="$1"
	EVT_VID="$2"

	NUM="$(vid_to_number "$EVT_VID")"
	TIME="$(date +%FT%H:%M:%S%z)"

	mkdir -p "$SXMO_LOGDIR"
	printf %b "$TIME\t$EVT_HANDLE\t$NUM\n" >> "$SXMO_LOGDIR/modemlog.tsv"
}

pickup() {
	CALLID="$1"

	DIRECTION="$(
		mmcli --voice-status -o "$CALLID" -K |
		grep call.properties.direction |
		cut -d: -f2 |
		tr -d " "
	)"
	case "$DIRECTION" in
		outgoing)
			if ! mmcli -m any -o "$CALLID" --start; then
				sxmo_notify_user.sh --urgency=critical "We failed to start the call"
				return 1
			fi

			sxmo_notify_user.sh "Started call"
			touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.initiatedcall"
			log_event "call_start" "$CALLID"
			;;
		incoming)
			sxmo_log "Invoking pickup hook (async)"
			sxmo_hook_pickup.sh &

			if ! mmcli -m any -o "$CALLID" --accept; then
				sxmo_notify_user.sh --urgency=critical "We failed to accept the call"
				return 1
			fi

			sxmo_notify_user.sh "Picked up call"
			touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.pickedupcall"
			log_event "call_pickup" "$CALLID"
			;;
		*)
			sxmo_notify_user.sh --urgency=critical "Couldn't initialize call with callid <$CALLID>; unknown direction <$DIRECTION>"
			# if we try to make an outgoing call while
			# already on an outgoing call, it crashes the modem and
			# gets us here.  We need to rm -rf
			# $XDG_RUNTIME_DIR/sxmo_call/* before we can call
			# again.
			#
			rm "$XDG_RUNTIME_DIR/sxmo_calls/"* 2>/dev/null || true
			rm -f "$XDG_RUNTIME_DIR"/sxmo.ring.pid 2>/dev/null
			rm -f "$SXMO_NOTIFDIR"/incomingcall* 2>/dev/null
			return 1
			;;
	esac
}

hangup() {
	CALLID="$1"

	if [ -f "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.pickedupcall" ]; then
		rm -f "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.pickedupcall"
		touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.hangedupcall"
		log_event "call_hangup" "$CALLID"

		sxmo_log "sxmo_modemcall: Invoking hangup hook (async)"
		sxmo_hook_hangup.sh &
	else
		#this call was never picked up and hung up immediately, so it is a discarded call
		touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.discardedcall"
		log_event "call_discard" "$CALLID"

		sxmo_log "sxmo_modemcall: Invoking discard hook (async)"
		sxmo_hook_discard.sh &
	fi

	if ! mmcli -m any -o "$CALLID" --hangup; then
		# we ignore already closed calls
		if list_active_calls | grep -q "/$CALLID "; then
			sxmo_notify_user.sh --urgency=critical "We failed to hangup the call"
			return 1
		fi
	fi
}

# We shallow muted/blocked and terminated calls
list_active_calls() {
	mmcli -m any --voice-list-calls | \
		awk '$1=$1' | \
		grep -v terminated | \
		grep -v "No calls were found" | while read -r line; do
			CALLID="$(printf "%s\n" "$line" | awk '$1=$1' | cut -d" " -f1 | xargs basename)"
			if [ -e "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.mutedring" ]; then
				continue # we shallow muted calls
			fi
			printf "%s\n" "$line"
	done
}

incall_menu() {
	# Note that mute mic does NOT actually work:
	# See: https://gitlab.com/mobian1/callaudiod/-/merge_requests/10

	# We have an active call
	while list_active_calls | grep -q . ; do
		CHOICES="$(grep . <<EOF
$icon_cls Close menu                ^ exit
$icon_aru Volume ($(sxmo_audio.sh vol get)) ^ sxmo_audio.sh vol up 20
$icon_ard Volume  ^ sxmo_audio.sh vol down 20
$(sxmo_modemaudio.sh is_enabled_speaker \
	&& printf "%s" "$icon_ton" \
	|| printf "%s" "$icon_tof"
) Speaker ^ sxmo_modemaudio.sh toggle_speaker
$(sxmo_modemaudio.sh is_muted_mic \
	&& printf "%s Mic ^ sxmo_modemaudio.sh unmute_mic" "$icon_tof" \
	|| printf "%s Mic ^ sxmo_modemaudio.sh mute_mic" "$icon_ton"
)
$icon_cfg Audio Settings ^ sxmo_audio.sh
$(
	list_active_calls | while read -r line; do
		CALLID="$(printf %s "$line" | cut -d" " -f1 | xargs basename)"
		NUMBER="$(vid_to_number "$CALLID")"
		CONTACT="$(sxmo_contacts.sh --name "$NUMBER")"
		[ "$CONTACT" = "???" ] && CONTACT="$NUMBER"
		case "$line" in
			*"(ringing-in)")
				# TODO switch to this call
				printf "%s Hangup %s ^ hangup %s\n" "$icon_phx" "$CONTACT" "$CALLID"
				printf "%s Ignore %s ^ mute %s\n" "$icon_phx" "$CONTACT" "$CALLID"
				;;
			*"(held)")
				# TODO switch to this call
				printf "%s Hangup %s ^ hangup %s\n" "$icon_phx" "$CONTACT" "$CALLID"
				;;
			*)
				printf "%s DTMF Tones %s ^ sxmo_terminal.sh sxmo_dtmf.sh %s\n" "$icon_mus" "$CONTACT" "$CALLID"
				printf "%s Hangup %s ^ hangup %s\n" "$icon_phx" "$CONTACT" "$CALLID"
				;;
		esac
	done
)
EOF
	)"


		PICKED="$(
			printf "%s\n" "$CHOICES" |
				cut -d'^' -f1 |
				sxmo_dmenu.sh -i -p "Incall Menu"
		)" || exit

		sxmo_log "Picked is $PICKED"

		CMD="$(printf "%s\n" "$CHOICES" | grep "$PICKED" | cut -d'^' -f2)"

		sxmo_log "Eval in call context: $CMD"
		eval "$CMD" || exit 1
	done & # To be killeable
	wait
}

mute() {
	CALLID="$1"

	# this signals that we muted this ring
	touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.mutedring"
	sxmo_log "Invoking mute_ring hook (async)"
	sxmo_hook_mute_ring.sh "$CONTACTNAME" &
	log_event "ring_mute" "$1"
}

# TODO Unify with pickup()
answerphone() {
	CALLID="$1"

	DIRECTION="$(
		mmcli --voice-status -o "$CALLID" -K |
		grep call.properties.direction |
		cut -d: -f2 |
		tr -d " "
	)"
	case "$DIRECTION" in
		outgoing)
			if ! mmcli -m any -o "$CALLID" --start; then
				sxmo_notify_user.sh --urgency=critical "We failed to start the call"
				return 1
			fi

			sxmo_notify_user.sh "Started call"
			touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.initiatedcall"
			log_event "call_start" "$CALLID"
			;;
		incoming)
			sxmo_log "Invoking answerphone hook (async)"
			sxmo_hook_answerphone.sh &

			if ! mmcli -m any -o "$CALLID" --accept; then
				sxmo_notify_user.sh --urgency=critical "We failed to accept the call"
				return 1
			fi

			sxmo_notify_user.sh "Answering Machine call"
			touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.answerphonecall"
			log_event "call_pickup" "$CALLID"
			;;
		*)
			sxmo_notify_user.sh --urgency=critical "Couldn't initialize call with callid <$CALLID>; unknown direction <$DIRECTION>"
			# if we try to make an outgoing call while
			# already on an outgoing call, it crashes the modem and
			# gets us here.  We need to rm -rf
			# $XDG_RUNTIME_DIR/sxmo_call/* before we can call
			# again.
			#
			rm "$XDG_RUNTIME_DIR/sxmo_calls/"* 2>/dev/null || true
			rm -f "$XDG_RUNTIME_DIR"/sxmo.ring.pid 2>/dev/null
			rm -f "$SXMO_NOTIFDIR"/answerphonecall* 2>/dev/null
			return 1
			;;
	esac
}

answerphone_menu() {
	# Note that mute mic does NOT actually work:
	# See: https://gitlab.com/mobian1/callaudiod/-/merge_requests/10

	# We have an active call
	while list_active_calls | grep -q . ; do
		CHOICES="$(grep . <<EOF
$icon_cls Close menu                ^ exit
$icon_aru Volume ($(sxmo_audio.sh vol get)) ^ sxmo_audio.sh vol up 20
$icon_ard Volume  ^ sxmo_audio.sh vol down 20
$(sxmo_modemaudio.sh is_enabled_speaker \
	&& printf "%s" "$icon_ton" \
	|| printf "%s" "$icon_tof"
) Speaker ^ sxmo_modemaudio.sh toggle_speaker
$icon_cfg Audio Settings ^ sxmo_audio.sh
$icon_phn Pick up ^ incall_menu
$icon_phx Hangup ^ hangup "$1"
EOF
	)"


		PICKED="$(
			printf "%s\n" "$CHOICES" |
				cut -d'^' -f1 |
				sxmo_dmenu.sh -i -p "Answerphone Menu"
		)" || exit

		sxmo_log "Picked is $PICKED"

		CMD="$(printf "%s\n" "$CHOICES" | grep "$PICKED" | cut -d'^' -f2)"

		sxmo_log "Eval in call context: $CMD"
		eval "$CMD" || exit 1
	done & # To be killeable
	wait
}

incoming_call_menu() {
	NUMBER="$(vid_to_number "$1")"
	CONTACTNAME="$(sxmo_contacts.sh --name "$NUMBER")"
	[ "$CONTACTNAME" = "???" ] && CONTACTNAME="$NUMBER"

	if [ "$SXMO_WM" = "sway" ]; then
		pickup_height="40"
	else
		pickup_height="100"
	fi

	(
		PICKED="$(
			cat <<EOF | sxmo_dmenu.sh -i -H "$pickup_height" -p "$CONTACTNAME"
$icon_phn Pickup
$icon_vcm Answerphone
$icon_phx Hangup
$icon_mut Ignore
EOF
		)" || exit

		case "$PICKED" in
			"$icon_phn Pickup")
				if ! sxmo_modemaudio.sh setup_audio; then
					sxmo_notify_user.sh --urgency=critical "We failed to setup call audio"
					return 1
				fi

				if ! pickup "$1"; then
					sxmo_notify_user.sh --urgency=critical "We failed to pickup the call"
					sxmo_modemaudio.sh reset_audio
					return 1
				fi

				incall_menu
				;;
			"$icon_vcm Answerphone")
				if ! sxmo_modemaudio.sh setup_audio; then
					sxmo_notify_user.sh --urgency=critical "We failed to setup call audio"
					return 1
				fi

				if ! answerphone "$1"; then
					sxmo_notify_user.sh --urgency=critical "We failed to answer the call"
					sxmo_modemaudio.sh reset_audio
					return 1
				fi

				answerphone_menu
				;;
			"$icon_phx Hangup")
				hangup "$1"
				;;
			"$icon_mut Ignore")
				mute "$1"
				;;
		esac
	) & # To be killeable
	wait
}

killed() {
	sxmo_dmenu.sh close
}
if [ "$1" = "incall_menu" ] || [ "answerphone_menu" ] || [ "$1" = "incoming_call_menu" ]; then
	trap 'killed' TERM INT
fi

"$@"

File sxmo_hook_answerphone.sh

#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors

# It appears to be that due to deliberate proprietary firmware (not hardware)
# limitations, PipeWire and PulseAudio might not be able to capture the audio
# received from the caller.
#
# The author of this message is urging you, the reader, to find a way to capture
# audio using PulseAudio or PipeWire or both.
#
# pinephone_modem_sdk release 0.7.1 (Record this call) offers in-call audio
# recording feature on Pinephone devices.

# This script is executed (asynchronously) when you pick up an incoming call

# kill existing ring playback
if [ -e "$XDG_RUNTIME_DIR/sxmo.ring.pid" ]; then
	xargs -r kill < "$XDG_RUNTIME_DIR/sxmo.ring.pid"
	rm "$XDG_RUNTIME_DIR/sxmo.ring.pid"
fi

# TODO Check if firmware is pinephone_modem_sdk

# Pause all media instances
sxmo_playerctl.sh pause_all

# Begin recording
# TODO SPEEX
# Use Speex https://speex.org/ the preferred codec for VoIP (e.g. Mumble and
# SIP) the filetype that is extenssively used by telephony companies and private
# intelligence agencies to store audio recodings of speech.
# TODO If pinephone_modem_sdk then use firmware to record
record mic dsnoop 1

# Mute microphone
# NOTE Audio microphone is required to capture audio on non-pinephone_modem_sdk.
# TODO If pinephone_modem_sdk then mute all microphones
# FIXME Mute microphone when call is engaged
sxmo_modemaudio.sh mute_mic

# Enable speaker
# FIXME Enable speaker when call is engaged
sxmo_modemaudio.sh enable_speaker

# Play audio 
mpv /usr/share/sxmo/answerphone.ogg

# TODO Add support for pinephone_modem_sdk
# TODO MUTE
# Mute microphone/audio entirely (e.g. sxmo_audio.sh) because firmware
# pinephone_modem_sdk is able to record directly from modem stream.

~kohn 2 months ago*

Apparently, the call audio doesn't go through PulseAudio. I'm investigating PipeWire.

If anyone can give a quick guidance, it would save time. Thank you

~kohn 2 months ago*

I need help with:

#sxmo_hook_answerphone.sh

  • speaker doesn't turn on at startup.
  • mute microphone at startup doesn't work <- regardless to callaudiod.
  • begin and end recording.

#sxmo_modemcall.sh

  • Hangup menu doesn't work.
Register here or Log in to comment, or comment via email.