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();
       }
     }

Reply via email to