{"id":1044,"date":"2025-09-17T19:00:00","date_gmt":"2025-09-17T19:00:00","guid":{"rendered":"https:\/\/james-batchelor.com\/?p=1044"},"modified":"2025-07-19T19:01:32","modified_gmt":"2025-07-19T19:01:32","slug":"sip-radio","status":"publish","type":"post","link":"https:\/\/james-batchelor.com\/index.php\/2025\/09\/17\/sip-radio\/","title":{"rendered":"SIP Radio"},"content":{"rendered":"\n<p>In a <a href=\"https:\/\/james-batchelor.com\/index.php\/2025\/02\/16\/sip-device-as-pi-audio-output\/\">previous post<\/a>, I hinted at the possibility of replacing a \u201csmart\u201d speaker with readily placed VoIP phones as a way to play radio around the house.<\/p>\n\n\n\n<p>This would kind of make sense, phones use the RTP protocol for audio is designed for real-time communication and so, naturally sync with each other in a local network.<\/p>\n\n\n\n<p>As a proof of concept, I wanted to create a service that allowed me to \u201cdial-in\u201d to a radio stream on demand&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-1024x577.jpg\" alt=\"\" class=\"wp-image-1045\" srcset=\"https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-1024x577.jpg 1024w, https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-300x169.jpg 300w, https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-768x432.jpg 768w, https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-1536x865.jpg 1536w, https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1-1200x676.jpg 1200w, https:\/\/james-batchelor.com\/wp-content\/uploads\/2025\/07\/sip-radio-1.jpg 1920w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/a><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p>Initial thoughts was to just to pipe a continuous radio stream to an extension. However, in addition to the waste of bandwidth, any network disruptions would essentially kill the stream without recovery. Therefore, a play on-demand service would help keep the stream fresh whilst saving bandwidth at idle.<\/p>\n\n\n\n<p>My preferred radio for testing is Kerrang radio, I get the URL\u2019s for radio feed via <a href=\"http:\/\/www.radiofeeds.co.uk\/mp3.asp\" target=\"_blank\" rel=\"noreferrer noopener\">this site<\/a> and downloading the playlist .pls file, then opening the file in a text editor to extract the actual stream URL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Baresip Setup<\/h2>\n\n\n\n<p>Similar to the earlier project in <a href=\"https:\/\/james-batchelor.com\/index.php\/2025\/02\/16\/sip-device-as-pi-audio-output\/\">piping audio from a Raspberry Pi to SIP<\/a>, a minimal install of Baresip will be used to handle the SIP element and added as a system service in a mostly similar way.<\/p>\n\n\n\n<p>To give the script some context on when to play on demand, we need a log of baresip&#8217;s output.<\/p>\n\n\n\n<p>In the service configuration file, under [service] change the following line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ExecStart=\/usr\/bin\/baresip<\/code><\/pre>\n\n\n\n<p>to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ExecStart=\/bin\/bash -c \"\/usr\/bin\/baresip > \/path\/to\/sipaudio.log 2>&amp;1\"<\/code><\/pre>\n\n\n\n<p>This will now run the application and send all output to a sipaudio.log file for processing by the script.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Script<\/h2>\n\n\n\n<p>The script will read the log file for any newly established calls and add them to a counter to establish how many calls are active, while the call count is greater than zero, trigger the radio stream.<\/p>\n\n\n\n<p>Similarly, call terminations are also registered and affect the <em>active_calls<\/em> variable.<\/p>\n\n\n\n<p>The goal is to ensure the stream is only triggered when the first active call is dectected, and only stop the stream when the last remaining call is cleared down. <\/p>\n\n\n\n<p>For example, if Phone A calls in, the stream is triggered and starts playing. Then, phone B also calls in and hears the established stream. If Phone A was to hangup, we&#8217;ll need to continue the stream for phone B (i.e not latching to the phone that triggered the stream), but if phone B also hangs up, the stream is stopped as there&#8217;s nothing there to listen.<\/p>\n\n\n\n<p>Create the script file and add the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\n# Path to Baresip log file\nLOG_FILE=\"\/path\/to\/sipaudio.log\"\nSTREAM_URL=\"http:\/\/edge-bauerall-01-gos2.sharp-stream.com\/kerrang.mp3?aw_0_1st.skey=1736072895\"\n\n# Track active calls\nactive_calls=0\nmpv_pid=\"\"\n\nstart_stream() {\n    if &#91;&#91; -z $mpv_pid ]]; then\n        echo \"Starting stream...\"\n        mpv \"$STREAM_URL\" &amp;\n        mpv_pid=$!\n    else\n        echo \"Stream is already running.\"\n    fi\n}\n\nstop_stream() {\n    if &#91;&#91; -n $mpv_pid ]]; then\n        echo \"Stopping stream...\"\n        kill $mpv_pid\n        wait $mpv_pid 2>\/dev\/null\n        mpv_pid=\"\"\n    else\n        echo \"Stream is not running.\"\n    fi\n}\n\nmonitor_calls() {\n    echo \"Monitoring Baresip log for call events...\"\n    tail -Fn0 \"$LOG_FILE\" | while read -r line; do\n        if &#91;&#91; \"$line\" == *\"Call established\"* ]]; then\n            ((active_calls++))\n            echo \"Call incoming. Active calls: $active_calls\"\n            if &#91;&#91; $active_calls -eq 1 ]]; then\n                start_stream\n            fi\n        elif &#91;&#91; \"$line\" == *\"session closed\"* ]]; then\n            ((active_calls--))\n            echo \"Call ended. Active calls: $active_calls\"\n            if &#91;&#91; $active_calls -le 0 ]]; then\n                active_calls=0\n                stop_stream\n            fi\n        fi\n    done\n}\n\n# Start monitoring calls\nmonitor_calls<\/code><\/pre>\n\n\n\n<p>Make the file executatble with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod +x \/path\/to\/filename.sh<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Service<\/h2>\n\n\n\n<p>This can be ran via the terminal\/SSH, but for ease of use and reboot survival, lets create a service for the script.<\/p>\n\n\n\n<p>Create and edit a service file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nano \/etc\/systemd\/system\/sip.radio.service<\/code><\/pre>\n\n\n\n<p>Add the following to the new service file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=Kerrang Radio Stream\nAfter=sound.target network.target\n\n&#91;Service]\nExecStart=\/path\/to\/filename.sh\nRestart=always\nRestartSec=10\nUser=pi\nWorkingDirectory=\/home\/pi\nStandardOutput=journal\nStandardError=journal\nEnvironment=HOME=\/home\/pi\nEnvironment=XDG_RUNTIME_DIR=\/run\/user\/1000\n\n&#91;Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p>When saved, reload services:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl daemon-reload<\/code><\/pre>\n\n\n\n<p>Start the service and enable it to start at boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl enable --now sipradio<\/code><\/pre>\n\n\n\n<p>Now a test call can be made to the baresip extension, and hopefully the radio will be though in a second or two.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>Since originally starting this in March, the script and SIP endpoint has been idle for a few months, but seeing if it still works while writing this, the stream fired right up on first asking.<\/p>\n\n\n\n<p>I would like to significantly reduce my &#8220;smart&#8221; speaker density, as they are almost exclusivley music players at this point due to the frustration in using them for anything else (even playing music is a challenge at times), but are always listening in.<\/p>\n\n\n\n<p>To put this theory into production will require both opus capable phone hardware and decent wired\/bluetooth speakers with connectivity inbetween.<\/p>\n\n\n\n<p>I wonder if a Pi Zero W2 could come to a cheap option rescue?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a previous post, I hinted at the possibility of replacing a \u201csmart\u201d speaker with readily placed VoIP phones as a way to play radio around the house. This would kind of make sense, phones use the RTP protocol for audio is designed for real-time communication and so, naturally sync with each other in a &hellip; <a href=\"https:\/\/james-batchelor.com\/index.php\/2025\/09\/17\/sip-radio\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;SIP Radio&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[212,247],"tags":[252,410,63,70,254,408,415],"class_list":["post-1044","post","type-post","status-publish","format-standard","hentry","category-network","category-voip","tag-asterisk","tag-baresip","tag-raspberry-pi","tag-rpi","tag-sip","tag-sip-audio","tag-sip-speaker"],"_links":{"self":[{"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/posts\/1044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/comments?post=1044"}],"version-history":[{"count":5,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/posts\/1044\/revisions"}],"predecessor-version":[{"id":1050,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/posts\/1044\/revisions\/1050"}],"wp:attachment":[{"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/media?parent=1044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/categories?post=1044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/james-batchelor.com\/index.php\/wp-json\/wp\/v2\/tags?post=1044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}