Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package noson for openSUSE:Factory checked in at 2021-04-14 10:11:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/noson (Old) and /work/SRC/openSUSE:Factory/.noson.new.2401 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "noson" Wed Apr 14 10:11:26 2021 rev:9 rq:885151 version:2.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/noson/noson.changes 2020-06-28 23:08:44.271339209 +0200 +++ /work/SRC/openSUSE:Factory/.noson.new.2401/noson.changes 2021-04-14 10:11:54.733588228 +0200 @@ -1,0 +2,7 @@ +Tue Apr 13 19:46:06 UTC 2021 - Bo Simonsen <[email protected]> + +- Update to 2.4.1 + * Fallback when presentation map is invalid for the service + * Includes improvements for pulse streamer + +------------------------------------------------------------------- Old: ---- 2.3.1.tar.gz New: ---- 2.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ noson.spec ++++++ --- /var/tmp/diff_new_pack.BTzb0N/_old 2021-04-14 10:11:55.169588965 +0200 +++ /var/tmp/diff_new_pack.BTzb0N/_new 2021-04-14 10:11:55.169588965 +0200 @@ -17,7 +17,7 @@ Name: noson -Version: 2.3.1 +Version: 2.4.1 Release: 0 Summary: C++ library for accessing sonos devices License: GPL-3.0-or-later ++++++ 2.3.1.tar.gz -> 2.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/CMakeLists.txt new/noson-2.4.1/CMakeLists.txt --- old/noson-2.3.1/CMakeLists.txt 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/CMakeLists.txt 2021-03-20 10:07:25.000000000 +0100 @@ -3,8 +3,8 @@ project(libnoson) -add_subdirectory(${CMAKE_SOURCE_DIR}/noson) -add_subdirectory(${CMAKE_SOURCE_DIR}/test) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/noson) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test) ############################################################################### # install targets diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/CMakeLists.txt new/noson-2.4.1/noson/CMakeLists.txt --- old/noson-2.3.1/noson/CMakeLists.txt 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/CMakeLists.txt 2021-03-20 10:07:25.000000000 +0100 @@ -3,12 +3,12 @@ project (noson) -set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") ############################################################################### # set lib version here set (noson_VERSION_MAJOR 2) -set (noson_VERSION_MINOR 3) +set (noson_VERSION_MINOR 4) set (noson_VERSION_PATCH 1) set (noson_VERSION ${noson_VERSION_MAJOR}.${noson_VERSION_MINOR}.${noson_VERSION_PATCH}) @@ -184,12 +184,12 @@ DESTINATION ${noson_PUBLIC_DIR}) file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/iodevice.h DESTINATION ${noson_PUBLIC_DIR}) -file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/streambuffer.h - DESTINATION ${noson_PUBLIC_DIR}) file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/streamreader.h DESTINATION ${noson_PUBLIC_DIR}) file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/filestreamer.h DESTINATION ${noson_PUBLIC_DIR}) +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/framebuffer.h + DESTINATION ${noson_PUBLIC_DIR}) if(HAVE_FLAC) file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/flacencoder.h DESTINATION ${noson_PUBLIC_DIR}) @@ -234,6 +234,7 @@ src/eventhandler.cpp src/filepicreader.cpp src/filestreamer.cpp + src/framebuffer.cpp src/imageservice.cpp src/intrinsic.cpp src/iodevice.cpp @@ -249,7 +250,6 @@ src/sonossystem.cpp src/sonostypes.cpp src/sonoszone.cpp - src/streambuffer.cpp src/subscription.cpp src/subscriptionpool.cpp src/zonegrouptopology.cpp @@ -272,6 +272,7 @@ src/eventhandler.h src/filepicreader.h src/filestreamer.h + src/framebuffer.h src/imageservice.h src/intrinsic.h src/iodevice.h @@ -288,7 +289,6 @@ src/sonossystem.h src/sonostypes.h src/sonoszone.h - src/streambuffer.h src/streamreader.h src/subscription.h src/subscriptionpool.h @@ -360,6 +360,13 @@ VERSION "${NOSON_LIB_VERSION}" SOVERSION "${NOSON_LIB_SOVERSION}") +# Support building as a subproject of a larger cmake project +target_include_directories(noson + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/public> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> + ) + # Export the package for use from the build-tree # (this registers the build-tree with a global CMake-registry) export(PACKAGE noson) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/audioencoder.cpp new/noson-2.4.1/noson/src/audioencoder.cpp --- old/noson-2.3.1/noson/src/audioencoder.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/audioencoder.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -28,6 +28,10 @@ { } +AudioEncoder::~AudioEncoder() +{ +} + void AudioEncoder::setAudioFormat(const AudioFormat& format) { if (IODevice::isOpen()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/audioencoder.h new/noson-2.4.1/noson/src/audioencoder.h --- old/noson-2.3.1/noson/src/audioencoder.h 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/audioencoder.h 2021-03-20 10:07:25.000000000 +0100 @@ -22,7 +22,6 @@ #include "local_config.h" #include "iodevice.h" #include "audioformat.h" -#include "streambuffer.h" namespace NSROOT { @@ -31,7 +30,7 @@ { public: AudioEncoder(); - virtual ~AudioEncoder() { } + virtual ~AudioEncoder(); void setAudioFormat(const AudioFormat& format); AudioFormat audioFormat() const { return m_format; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/audiosource.cpp new/noson-2.4.1/noson/src/audiosource.cpp --- old/noson-2.3.1/noson/src/audiosource.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/audiosource.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -17,30 +17,39 @@ */ #include "audiosource.h" -#include "streambuffer.h" +#include "framebuffer.h" using namespace NSROOT; -#define BUFFER_SIZE 0x10000 +#define FRAME_BUFFER_SIZE 256 AudioSource::AudioSource() -: AudioSource(BUFFER_SIZE) +: AudioSource(FRAME_BUFFER_SIZE) { } AudioSource::AudioSource(int buffered) : m_record(false) -, m_buffer(new StreamBuffer(buffered)) +, m_buffer(nullptr) +, m_packet(nullptr) +, m_consumed(0) +, m_mute(false) { + m_buffer = new FrameBuffer(buffered); } AudioSource::~AudioSource() { + if (m_packet) + m_buffer->freePacket(m_packet); delete m_buffer; } bool AudioSource::startRecording() { + if (m_packet) + m_buffer->freePacket(m_packet); + m_packet = nullptr; m_buffer->clear(); m_record = true; return true; @@ -53,12 +62,37 @@ int AudioSource::bytesAvailable() const { - return m_buffer->size(); + if (m_packet) + return (m_packet->size - m_consumed); + return m_buffer->bytesAvailable(); +} + +void AudioSource::mute(bool enabled) +{ + m_mute = enabled; } int AudioSource::readData(char * data, int maxlen) { - return m_buffer->read(data, maxlen); + if (m_packet == nullptr) + { + m_packet = m_buffer->read(); + m_consumed = 0; + } + if (m_packet) + { + int s = m_packet->size - m_consumed; + int r = (maxlen < s ? maxlen : s); + memcpy(data, m_packet->data + m_consumed, r); + m_consumed += r; + if (m_consumed >= m_packet->size) + { + m_buffer->freePacket(m_packet); + m_packet = nullptr; + } + return r; + } + return 0; } int AudioSource::writeData(const char * data, int len) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/audiosource.h new/noson-2.4.1/noson/src/audiosource.h --- old/noson-2.3.1/noson/src/audiosource.h 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/audiosource.h 2021-03-20 10:07:25.000000000 +0100 @@ -28,7 +28,8 @@ namespace NSROOT { -class StreamBuffer; +class FrameBuffer; +class FramePacket; class AudioSource : public IODevice { @@ -76,13 +77,19 @@ void stopRecording(); int bytesAvailable() const override; + void mute(bool enabled); + bool muted() const { return m_mute; } + protected: int readData(char * data, int maxlen) override; int writeData(const char *data, int len) override; + volatile bool m_mute; private: bool m_record; - StreamBuffer * m_buffer; + FrameBuffer * m_buffer; + FramePacket * m_packet; + int m_consumed; }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/flacencoder.cpp new/noson-2.4.1/noson/src/flacencoder.cpp --- old/noson-2.3.1/noson/src/flacencoder.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/flacencoder.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -17,17 +17,17 @@ */ #include "flacencoder.h" -#include "streambuffer.h" +#include "framebuffer.h" #include "private/byteorder.h" #include "private/debug.h" #define SAMPLES 1024 -#define BUFFER_SIZE 0x10000 +#define FRAME_BUFFER_SIZE 256 using namespace NSROOT; FLACEncoder::FLACEncoder() -: FLACEncoder(BUFFER_SIZE) +: FLACEncoder(FRAME_BUFFER_SIZE) { } @@ -38,9 +38,12 @@ , m_sampleSize(0) , m_pcm(nullptr) , m_buffer(nullptr) -, m_encoder(this) +, m_packet(nullptr) +, m_consumed(0) +, m_encoder(nullptr) { - m_buffer = new StreamBuffer(buffered); + m_buffer = new FrameBuffer(buffered); + m_encoder = new FLACEncoderPrivate(this); } FLACEncoder::~FLACEncoder() @@ -49,6 +52,9 @@ AudioEncoder::close(); if (m_pcm != nullptr) delete[] m_pcm; + if (m_packet) + m_buffer->freePacket(m_packet); + delete m_encoder; delete m_buffer; } @@ -65,15 +71,15 @@ // configure the encoder if (!(m_ok = m_format.isValid())) DBG(DBG_WARN, "ERROR: Invalid format\n"); - else if (!(m_ok = m_encoder.set_verify(true))) + else if (!(m_ok = m_encoder->set_verify(true))) DBG(DBG_WARN, "ERROR: Set verify failed\n"); - else if (!(m_ok = m_encoder.set_compression_level(5))) + else if (!(m_ok = m_encoder->set_compression_level(5))) DBG(DBG_WARN, "ERROR: Set compression level failed\n"); - else if (!(m_ok = m_encoder.set_channels(m_format.channelCount))) + else if (!(m_ok = m_encoder->set_channels(m_format.channelCount))) DBG(DBG_WARN, "ERROR: Set channels (%d) failed\n", m_format.channelCount); - else if (!(m_ok = m_encoder.set_bits_per_sample(m_format.sampleSize))) + else if (!(m_ok = m_encoder->set_bits_per_sample(m_format.sampleSize))) DBG(DBG_WARN, "ERROR: Set sample size (%d) failed\n", m_format.sampleSize); - else if (!(m_ok = m_encoder.set_sample_rate(m_format.sampleRate))) + else if (!(m_ok = m_encoder->set_sample_rate(m_format.sampleRate))) DBG(DBG_WARN, "ERROR: Set sample rate (%d) failed\n", m_format.sampleRate); else if (!(m_ok = (m_format.sampleSize == 8 && m_format.sampleType == AudioFormat::UnSignedInt) || (m_format.sampleSize == 16 && m_format.sampleType == AudioFormat::SignedInt && m_format.byteOrder == AudioFormat::LittleEndian) || @@ -93,7 +99,7 @@ m_buffer->clear(); AudioEncoder::open(mode); - FLAC__StreamEncoderInitStatus init_status = m_encoder.init(); + FLAC__StreamEncoderInitStatus init_status = m_encoder->init(); if(init_status == FLAC__STREAM_ENCODER_INIT_STATUS_OK) return true; AudioEncoder::close(); @@ -103,12 +109,32 @@ int FLACEncoder::bytesAvailable() const { - return m_buffer->size(); + if (m_packet) + return (m_packet->size - m_consumed); + return m_buffer->bytesAvailable(); } int FLACEncoder::readData(char * data, int maxlen) { - return m_buffer->read(data, maxlen); + if (m_packet == nullptr) + { + m_packet = m_buffer->read(); + m_consumed = 0; + } + if (m_packet) + { + int s = m_packet->size - m_consumed; + int r = (maxlen < s ? maxlen : s); + memcpy(data, m_packet->data + m_consumed, r); + m_consumed += r; + if (m_consumed >= m_packet->size) + { + m_buffer->freePacket(m_packet); + m_packet = nullptr; + } + return r; + } + return 0; } void FLACEncoder::onClose() @@ -116,7 +142,7 @@ if (AudioEncoder::isOpen()) { DBG(DBG_INFO, "Close FLAC encoder\n"); - m_encoder.finish(); + m_encoder->finish(); } } @@ -153,7 +179,7 @@ } } // feed samples to encoder - ok = m_encoder.process_interleaved(m_pcm, need); + ok = m_encoder->process_interleaved(m_pcm, need); samples -= need; } return len; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/flacencoder.h new/noson-2.4.1/noson/src/flacencoder.h --- old/noson-2.3.1/noson/src/flacencoder.h 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/flacencoder.h 2021-03-20 10:07:25.000000000 +0100 @@ -28,7 +28,8 @@ namespace NSROOT { -class StreamBuffer; +class FrameBuffer; +class FramePacket; class FLACEncoder : public AudioEncoder { @@ -57,7 +58,9 @@ int m_sampleSize; FLAC__int32 * m_pcm; - StreamBuffer * m_buffer; + FrameBuffer * m_buffer; + FramePacket * m_packet; + int m_consumed; class FLACEncoderPrivate : public FLAC::Encoder::Stream { @@ -68,7 +71,7 @@ FLACEncoder * m_p; }; - FLACEncoderPrivate m_encoder; + FLACEncoderPrivate * m_encoder; }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/framebuffer.cpp new/noson-2.4.1/noson/src/framebuffer.cpp --- old/noson-2.3.1/noson/src/framebuffer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/noson-2.4.1/noson/src/framebuffer.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2021 Jean-Luc Barriere + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "framebuffer.h" + +#include "private/os/threads/mutex.h" +#include "private/debug.h" + +using namespace NSROOT; + +namespace NSROOT +{ + struct FrameBuffer::Lockable + { + OS::CMutex mutex; + }; +} + +FramePacket::FramePacket(int _capacity) +: id(0) +, size(_capacity) +, data(new char [_capacity]) +, capacity(_capacity) +{ +} + +FramePacket::~FramePacket() +{ + if (data) + delete [] data; +} + +FrameBuffer::FrameBuffer(int capacity) +: m_lock(new Lockable()) +, m_capacity(capacity) +, m_count(0) +, m_buffer() +, m_read(nullptr) +, m_write(nullptr) +, m_pool() +{ + assert(capacity > 0); + m_buffer.resize(capacity); + init(); +} + +FrameBuffer::~FrameBuffer() +{ + OS::CLockGuard g(m_lock->mutex); + for (std::vector<Frame*>::iterator it = m_buffer.begin(); it != m_buffer.end(); ++it) + delete *it; + while (!m_pool.empty()) + { + delete m_pool.front(); + m_pool.pop_front(); + } +} + +void FrameBuffer::init() +{ + Frame * previous = nullptr; + for (std::vector<Frame*>::iterator it = m_buffer.begin(); it != m_buffer.end(); ++it) + { + *it = new Frame(); + if (previous) + previous->next = *it; + previous = *it; + } + if (m_buffer.begin() != m_buffer.end()) + previous->next = *(m_buffer.begin()); + m_write = *(m_buffer.begin()); + m_read = m_write; +} + +int FrameBuffer::capacity() const +{ + return m_capacity; +} + +int FrameBuffer::bytesAvailable() const +{ + OS::CLockGuard g(m_lock->mutex); + return (m_read != m_write ? m_read->packet->size : 0); +} + +void FrameBuffer::clear() +{ + OS::CLockGuard g(m_lock->mutex); + m_count = 0; + m_read = m_write; +} + +int FrameBuffer::write(const char * data, int len) +{ + if (len > 0) + { + FramePacket * _packet = needPacket(len); + _packet->size = len; + memcpy(_packet->data, data, len); + { + OS::CLockGuard g(m_lock->mutex); + if (m_write->packet) + freePacket(m_write->packet); + m_write->packet = _packet; + m_write->packet->id = ++m_count; + m_write = m_write->next; + } + } + return len; +} + +FramePacket * FrameBuffer::read() +{ + FramePacket * p = nullptr; + { + OS::CLockGuard g(m_lock->mutex); + if (m_read != m_write) + { + p = m_read->packet; + m_read->packet = nullptr; + m_read = m_read->next; + } + } + return p; +} + +void FrameBuffer::freePacket(FramePacket * p) +{ + m_pool.push_back(p); +} + +FramePacket * FrameBuffer::needPacket(int size) +{ + FramePacket * p = nullptr; + if (!m_pool.empty()) + { + p = m_pool.front(); + m_pool.pop_front(); + if (p->capacity >= size) + { + p->id = 0; + return p; + } + delete p; + } + return new FramePacket(size); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/framebuffer.h new/noson-2.4.1/noson/src/framebuffer.h --- old/noson-2.3.1/noson/src/framebuffer.h 1970-01-01 01:00:00.000000000 +0100 +++ new/noson-2.4.1/noson/src/framebuffer.h 2021-03-20 10:07:25.000000000 +0100 @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 Jean-Luc Barriere + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef FRAMEBUFFER_H +#define FRAMEBUFFER_H + +#include "local_config.h" + +#include <cstring> +#include <cassert> +#include <vector> +#include <list> + +namespace NSROOT +{ + +class FramePacket +{ +public: + FramePacket(int _capacity); + ~FramePacket(); + unsigned id; + int size; + char * const data; + const int capacity; +private: + // prevent copy + FramePacket(const FramePacket& other); + FramePacket& operator=(const FramePacket& other); +}; + +class FrameBuffer +{ +public: + FrameBuffer(int capacity); + virtual ~FrameBuffer(); + + int capacity() const; + + int bytesAvailable() const; + + void clear(); + + int write(const char * data, int len); + + /** + * Returned pointer MUST BE freed by caller + * @see freePacket(FramePacket *) + * @return new FramePacket or nullptr + */ + FramePacket * read(); + + void freePacket(FramePacket * p); + +private: + // Prevent copy + FrameBuffer(const FrameBuffer& other); + FrameBuffer& operator=(const FrameBuffer& other); + +private: + struct Lockable; + mutable Lockable * m_lock; + const int m_capacity; /// buffer size + volatile unsigned m_count; /// total count of processed frame + + struct Frame + { + Frame() : packet(nullptr), next(nullptr) { } + ~Frame() { if (packet) delete packet; } + FramePacket * packet; + Frame * next; + }; + + std::vector<Frame*> m_buffer; /// buffer of frames + volatile Frame * m_read; /// frame to read + volatile Frame * m_write; /// frame to write + + void init(); + + std::list<FramePacket*> m_pool; + FramePacket * needPacket(int size); +}; + +} + +#endif /* FRAMEBUFFER_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/pasource.cpp new/noson-2.4.1/noson/src/pasource.cpp --- old/noson-2.3.1/noson/src/pasource.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/pasource.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -62,7 +62,6 @@ , m_pa(nullptr) , m_blankKiller(nullptr) , m_p(new PASourceWorker(this)) - { } @@ -200,6 +199,8 @@ DBG(DBG_ERROR, "pa_simple_read() failed: %s\n", pa_strerror(m_source->m_pa_error)); break; } + if (m_source->m_mute) + memset(buf, 0, bsize); // Apply the blank killer m_source->m_blankKiller(buf, channels, BLANK_FRAMES); // And write it to out diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/pulsestreamer.cpp new/noson-2.4.1/noson/src/pulsestreamer.cpp --- old/noson-2.3.1/noson/src/pulsestreamer.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/pulsestreamer.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -26,6 +26,7 @@ #include "data/datareader.h" #include "private/debug.h" #include "private/socket.h" +#include "private/os/threads/timeout.h" #include <cstring> @@ -36,13 +37,14 @@ #define PULSESTREAMER_TIMEOUT 10000 #define PULSESTREAMER_MAX_PB 3 #define PULSESTREAMER_CHUNK 16384 +#define PULSESTREAMER_TM_MUTE 1000 #define PA_SINK_NAME "noson" #define PA_CLIENT_NAME PA_SINK_NAME using namespace NSROOT; PulseStreamer::PulseStreamer(RequestBroker * imageService /*= nullptr*/) -: SONOS::RequestBroker() +: RequestBroker() , m_resources() , m_sinkIndex(0) , m_playbackCount(0) @@ -130,19 +132,19 @@ std::string PulseStreamer::GetPASink() { std::string deviceName; - SONOS::PAControl::SinkList sinks; - SONOS::PAControl pacontrol(PA_CLIENT_NAME); + PAControl::SinkList sinks; + PAControl pacontrol(PA_CLIENT_NAME); if (pacontrol.connect()) { bool cont = true; for (;;) { pacontrol.getSinkList(&sinks); - for (SONOS::PAControl::Sink ad : sinks) + for (PAControl::Sink ad : sinks) { if (ad.name == PA_SINK_NAME) { - SONOS::DBG(DBG_DEBUG, "%s: Found device %d: %s\n", __FUNCTION__, ad.index, ad.monitorSourceName.c_str()); + DBG(DBG_DEBUG, "%s: Found device %d: %s\n", __FUNCTION__, ad.index, ad.monitorSourceName.c_str()); deviceName = ad.monitorSourceName; m_sinkIndex.Store(ad.ownerModule); // own the module break; @@ -163,10 +165,10 @@ { // Lock count // and check if an other playback is running before delete the sink - SONOS::LockedNumber<int>::pointer p = m_playbackCount.Get(); + LockedNumber<int>::pointer p = m_playbackCount.Get(); if (*p == 1 && m_sinkIndex.Load()) { - SONOS::PAControl pacontrol(PA_CLIENT_NAME); + PAControl pacontrol(PA_CLIENT_NAME); if (pacontrol.connect()) { DBG(DBG_DEBUG, "%s: delete sink (%s)\n", __FUNCTION__, PA_SINK_NAME); @@ -192,9 +194,12 @@ Reply429(handle); else { - SONOS::AudioSource * src = new SONOS::PASource(PA_CLIENT_NAME, deviceName); - SONOS::AudioEncoder * enc = new SONOS::FLACEncoder(); - SONOS::AudioStream ai(*src, *enc); + AudioSource * src = new PASource(PA_CLIENT_NAME, deviceName); + AudioEncoder * enc = new FLACEncoder(); + AudioStream ai(*src, *enc); + // the source is muted for a short time to limit output rate on startup + OS::CTimeout muted(PULSESTREAMER_TM_MUTE); + src->mute(true); ai.start(); std::string resp; @@ -215,6 +220,9 @@ memcpy(buf + r + 7, "\r\n", 2); if (!RequestBroker::Reply(handle, buf, r + 7 + 2)) break; + // disable source mute after delay + if (src->muted() && !muted.TimeLeft()) + src->mute(false); } delete [] buf; if (r == 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/smapi.cpp new/noson-2.4.1/noson/src/smapi.cpp --- old/noson-2.3.1/noson/src/smapi.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/smapi.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -120,25 +120,29 @@ default: break; } - if (!response->IsSuccessful()) + if (response->IsSuccessful()) { - DBG(DBG_ERROR, "%s: invalid response\n", __FUNCTION__); + // receive content data + size_t len = 0, l = 0; + std::string data; + char buffer[4096]; + while ((l = response->ReadContent(buffer, sizeof(buffer)))) + { + data.append(buffer, l); + len += l; + } delete response; - return false; + response = nullptr; + if (!parsePresentationMap(data)) + return false; + } + else + { + DBG(DBG_ERROR, "%s: the presentation map is invalid\n", __FUNCTION__); + delete response; + m_presentation.clear(); + m_searchCategories.clear(); } - // receive content data - size_t len = 0, l = 0; - std::string data; - char buffer[4096]; - while ((l = response->ReadContent(buffer, sizeof(buffer)))) - { - data.append(buffer, l); - len += l; - } - delete response; - response = nullptr; - if (!parsePresentationMap(data)) - return false; } // see https://musicpartners.sonos.com/node/530 @@ -147,11 +151,15 @@ { if (m_searchCategories.empty()) { - // add default search categories - m_searchCategories.push_back(ElementPtr(new Element("tracks", "track"))); - m_searchCategories.push_back(ElementPtr(new Element("albums", "album"))); - m_searchCategories.push_back(ElementPtr(new Element("artists", "artist"))); - m_searchCategories.push_back(ElementPtr(new Element("playlists", "playlist"))); + // don't load default categories for TuneIn because it won't work as expected + if (m_service->GetServiceType() != "65031") /* TuneIn */ + { + // add default search categories + m_searchCategories.push_back(ElementPtr(new Element("tracks", "track"))); + m_searchCategories.push_back(ElementPtr(new Element("albums", "album"))); + m_searchCategories.push_back(ElementPtr(new Element("artists", "artist"))); + m_searchCategories.push_back(ElementPtr(new Element("playlists", "playlist"))); + } } } else @@ -621,6 +629,7 @@ WSRequest request(*m_uri, HRM_POST); request.SetUserAgent(m_service->GetAgent()); + request.SetHeader("X-Sonos-SWGen", "1"); request.SetHeader("Accept-Language", m_language); request.SetHeader("SOAPAction", soapaction); request.SetContentCustom(CT_XML, content.c_str()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/sonosplayer.cpp new/noson-2.4.1/noson/src/sonosplayer.cpp --- old/noson-2.3.1/noson/src/sonosplayer.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/sonosplayer.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -519,7 +519,7 @@ if (mime == ".flac") { std::string protocolInfo; - protocolInfo.assign(ProtocolTable[Protocol_httpGet]).append(":*:audio/flac:*"); + protocolInfo.assign(ProtocolTable[Protocol_xRinconMP3Radio]).append(":*:audio/flac:*"); // Setup the digital item DigitalItemPtr item(new DigitalItem(DigitalItem::Type_item, DigitalItem::SubType_audioItem)); item->SetProperty(DIDL_QNAME_DC "title", title); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/streambuffer.cpp new/noson-2.4.1/noson/src/streambuffer.cpp --- old/noson-2.3.1/noson/src/streambuffer.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/streambuffer.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2018-2019 Jean-Luc Barriere - * - * 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 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "streambuffer.h" - -#include "private/os/threads/mutex.h" - -using namespace NSROOT; - -namespace NSROOT -{ - struct StreamBuffer::Lockable - { - OS::CMutex mutex; - }; -} - -StreamBuffer::StreamBuffer(int capacity) -: m_lock(new Lockable()) -, m_buffer(new char [capacity]) -, m_capacity(capacity) -, m_wx(0) -, m_rx(0) -, m_reset(false) -{ - assert(capacity > 0); -} - -StreamBuffer::~StreamBuffer () -{ - delete [] m_buffer; - delete m_lock; -} - -int StreamBuffer::capacity () const -{ - return m_capacity; -} - -int StreamBuffer::size () const -{ - m_lock->mutex.Lock (); - int left = m_wx - m_rx; - m_lock->mutex.Unlock (); - return left > m_capacity ? m_capacity : left; -} - -void StreamBuffer::clear () -{ - m_lock->mutex.Lock (); - m_wx = m_rx = 0; - m_reset = true; - m_lock->mutex.Unlock (); -} - -int StreamBuffer::write (const char * data, int len) -{ - m_lock->mutex.Lock (); - int wx = m_wx; - m_reset = false; - m_lock->mutex.Unlock (); - int left = len; - while (left > 0) - { - int p = wx % m_capacity; - int l = m_capacity - p; - if (l > left) - l = left; - memcpy (m_buffer + p, data, l); - m_lock->mutex.Lock (); - wx = m_reset ? m_wx : (m_wx += l); - m_reset = false; - m_lock->mutex.Unlock (); - data += l; - left -= l; - } - m_lock->mutex.Unlock (); - return len; -} - -int StreamBuffer::read (char * data, int maxlen) -{ - m_lock->mutex.Lock (); - int wx = m_wx; - m_lock->mutex.Unlock (); - // adjust available bytes - int left = wx - m_rx; - if (left > m_capacity) - { - m_rx = wx - m_capacity; - left = m_capacity; - } - if (left > maxlen) - left = maxlen; - else - maxlen = left; - while (left > 0) - { - int p = m_rx % m_capacity; - int l = m_capacity - p; - if (l > left) - l = left; - memcpy (data, m_buffer + p, l); - m_rx += l; - data += l; - left -= l; - } - return (maxlen - left); -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/streambuffer.h new/noson-2.4.1/noson/src/streambuffer.h --- old/noson-2.3.1/noson/src/streambuffer.h 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/streambuffer.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2018-2019 Jean-Luc Barriere - * - * 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 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef STREAMBUFFER_H -#define STREAMBUFFER_H - -#include "local_config.h" - -#include <cstring> -#include <cassert> - -namespace NSROOT -{ - -class StreamBuffer -{ -public: - StreamBuffer(int capacity); - virtual ~StreamBuffer(); - - int capacity() const; - - int size() const; - - void clear(); - - int write(const char * data, int len); - - int read(char * data, int maxlen); - -private: - // Prevent copy - StreamBuffer(const StreamBuffer& other); - StreamBuffer& operator=(const StreamBuffer& other); - -private: - struct Lockable; - mutable Lockable * m_lock; - char * m_buffer; - const int m_capacity; - volatile int m_wx; - volatile int m_rx; - volatile bool m_reset; -}; - -} - -#endif /* STREAMBUFFER_H */ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/noson-2.3.1/noson/src/subscription.cpp new/noson-2.4.1/noson/src/subscription.cpp --- old/noson-2.3.1/noson/src/subscription.cpp 2020-05-06 19:14:21.000000000 +0200 +++ new/noson-2.4.1/noson/src/subscription.cpp 2021-03-20 10:07:25.000000000 +0100 @@ -93,6 +93,7 @@ { if (IsRunning()) { + m_timeout.Clear(); m_event.Signal(); } }
