diff --git a/README b/README index 8a9743c..4861eda 100644 --- a/README +++ b/README @@ -1,6 +1,11 @@ -OpenHome Sample Players (https://github.com/openhome/ohPlayer) for Mac +OpenHome Sample Player (https://github.com/openhome/ohPlayer) for Mac Windows, Linux and Raspberry Pi. +========================================= +Only the Linux tree is under development. +========================================= + + Repository and source setup =========================== diff --git a/linux/ConfigGTKKeyStore.cpp b/linux/ConfigGTKKeyStore.cpp index e12685f..d8eaebf 100644 --- a/linux/ConfigGTKKeyStore.cpp +++ b/linux/ConfigGTKKeyStore.cpp @@ -1,7 +1,6 @@ #include #include -#include #include #include diff --git a/linux/ConfigGTKKeyStore.h b/linux/ConfigGTKKeyStore.h index 3f88a33..ebc8727 100644 --- a/linux/ConfigGTKKeyStore.h +++ b/linux/ConfigGTKKeyStore.h @@ -2,10 +2,12 @@ #include -#include +#include #include #include +#include + namespace OpenHome { namespace Configuration { diff --git a/linux/DriverAlsa.cpp b/linux/DriverAlsa.cpp index 724fd0f..cba1083 100644 --- a/linux/DriverAlsa.cpp +++ b/linux/DriverAlsa.cpp @@ -50,11 +50,11 @@ class PcmProcessorBase : public IPcmProcessor protected: PcmProcessorBase(IDataSink& aDataSink, Bwx& aBuffer); public: // IPcmProcessor - virtual void BeginBlock(); + virtual void BeginBlock() override; void ProcessFragment(const Brx& aData, TUint aNumChannels, TUint aSubsampleBytes) override; void ProcessSilence(const Brx& aData, TUint aNumChannels, TUint aSubsampleBytes) override; - virtual void EndBlock(); - virtual void Flush(); + virtual void EndBlock() override; + virtual void Flush() override; public: void SetDuplicateChannel(TBool duplicateChannel); void SetBitDepth(TUint bitDepth); @@ -993,14 +993,30 @@ TUint DriverAlsa::PipelineAnimatorDelayJiffies(AudioFormat aFormat, return iPimpl->DriverDelayJiffies(aSampleRate); } -TUint DriverAlsa::PipelineAnimatorDsdBlockSizeWords() const +TUint DriverAlsa::PipelineAnimatorMaxBitDepth() const { - return 0; + return 0; } -TUint DriverAlsa::PipelineAnimatorMaxBitDepth() const +void DriverAlsa::PipelineAnimatorDsdBlockConfiguration(TUint& aSampleBlockWords, + TUint& aPadBytesPerChunk) const { - return 0; + aSampleBlockWords=0; + aPadBytesPerChunk=0; +} + + + +void DriverAlsa::PipelineAnimatorGetMaxSampleRates(TUint& aPcm, TUint& aDsd) const +{ + aPcm=0; + aDsd=0; +} + +void DriverAlsa::PipelineAnimatorGetMaxSampleRates(TUint& aPcm, TUint& aDsd) const +{ + aPcm = 192000; + aDsd = 5644800; } Msg* DriverAlsa::ProcessMsg(MsgHalt* aMsg) @@ -1044,3 +1060,6 @@ Msg* DriverAlsa::ProcessMsg(MsgDrain* aMsg) return aMsg; } + + + diff --git a/linux/DriverAlsa.h b/linux/DriverAlsa.h index 0d3155f..2cb4508 100644 --- a/linux/DriverAlsa.h +++ b/linux/DriverAlsa.h @@ -42,8 +42,12 @@ class DriverAlsa : public PipelineElement, public IPipelineAnimator, private INo TUint PipelineAnimatorBufferJiffies() const override; TUint PipelineAnimatorDelayJiffies(AudioFormat aFormat, TUint aSampleRate, TUint aBitDepth, TUint aNumChannels) const override; - TUint PipelineAnimatorDsdBlockSizeWords() const override; TUint PipelineAnimatorMaxBitDepth() const override; + + void PipelineAnimatorDsdBlockConfiguration(TUint& aSampleBlockWords, + TUint& aPadBytesPerChunk) const override; + void PipelineAnimatorGetMaxSampleRates(TUint& aPcm, TUint& aDsd) const override; + private: class Pimpl; Pimpl* iPimpl; diff --git a/linux/ExampleMediaPlayer.cpp b/linux/ExampleMediaPlayer.cpp index 8b490bf..7ad58bc 100644 --- a/linux/ExampleMediaPlayer.cpp +++ b/linux/ExampleMediaPlayer.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "ConfigGTKKeyStore.h" #include "ControlPointProxy.h" @@ -40,6 +41,9 @@ using namespace OpenHome::Web; const Brn kPrefix("OpenHome"); const Brn ExampleMediaPlayer::kIconOpenHomeFileName("OpenHomeIcon"); +const Brn ExampleMediaPlayer::kResourceDir(Brn("/usr/share/" + "openhome-player/res/")); +const Brn ExampleMediaPlayer::kPlayerName("Softplayer"); ExampleMediaPlayer::ExampleMediaPlayer(Net::DvStack& aDvStack, Net::CpStack& aCpStack, @@ -116,10 +120,12 @@ ExampleMediaPlayer::ExampleMediaPlayer(Net::DvStack& aDvStack, iInitParams->SetGorgerDuration(iInitParams->DecodedReservoirJiffies()); // create MediaPlayer - auto mpInit = MediaPlayerInitParams::New(Brn(aRoom), Brn(aProductName), kPrefix); - iMediaPlayer = new MediaPlayer( aDvStack, aCpStack, *iDevice, *iRamStore, + iAudioTime = new AudioTimeCpu(aDvStack.Env()); + auto mpInit = MediaPlayerInitParams::New(Brn(aRoom), Brn(aProductName), kPrefix); + + iMediaPlayer = new MediaPlayer( aDvStack, aCpStack, *iDevice, *iRamStore, *iConfigStore, iInitParams, - volumeInit, volumeProfile, *iInfoLogger, + *iAudioTime, volumeInit, volumeProfile, *iInfoLogger, aUdn, mpInit); #ifdef DEBUG @@ -167,6 +173,7 @@ ExampleMediaPlayer::~ExampleMediaPlayer() delete iDevice; delete iDeviceUpnpAv; delete iRamStore; + delete iAudioTime; } Environment& ExampleMediaPlayer::Env() @@ -325,24 +332,31 @@ void ExampleMediaPlayer::RegisterPlugins(Environment& aEnv) #ifdef ENABLE_TIDAL // You must define your Tidal token + std::vector aAppDetails; + aAppDetails.emplace_back(TildaAuthAppId, TildaAuthClientId, TildaAuthClientSecret); + iMediaPlayer->Add(ProtocolFactory::NewTidal( aEnv, - Brn(TIDAL_TOKEN), + ssl, + TildaAuthClientId, + TildaAuthClientSecret, + aAppDetails, *iMediaPlayer)); #endif // ENABLE_TIDAL #ifdef ENABLE_QOBUZ // You must define your QOBUZ appId and secret key iMediaPlayer->Add(ProtocolFactory::NewQobuz( - Brn(QOBUZ_APPID), - Brn(QOBUZ_SECRET), - *iMediaPlayer)); + QoubusAuthClientId, + QoubusAuthClientSecret, + *iMediaPlayer, + iUserAgent)); #endif // ENABLE_QOBUZ #ifdef ENABLE_RADIO // Radio is disabled by default as many stations depend on AAC iMediaPlayer->Add(SourceFactory::NewRadio(*iMediaPlayer, - Brn(TUNEIN_PARTNER_ID))); + TuneinAuthPartnerId)); #endif // ENABLE_RADIO } @@ -380,12 +394,13 @@ void ExampleMediaPlayer::AddConfigApp() iMediaPlayer->ConfigManager(), iFileResourceHandlerFactory, sourcesBufs, - Brn("Softplayer"), - Brn("/usr/share/" - "openhome-player/res/"), - 30, + kPlayerName, + kResourceDir, + kMinWebUiResourceThreads, kMaxUiTabs, kUiSendQueueSize, + kUiMsgBufCount, + kUiMsgBufBytes, iRebootHandler); iAppFramework->Add(iConfigApp, // iAppFramework takes ownership @@ -425,7 +440,7 @@ OpenHome::Net::Library* ExampleMediaPlayerInit::CreateLibrary(TIpAddress preferr { TUint index = 0; InitialisationParams *initParams = InitialisationParams::Create(); - TIpAddress lastSubnet = InitArgs::NO_SUBNET; + TIpAddress lastSubnet = TIpAddress(); const TChar *lastSubnetStr = "Subnet.LastUsed"; //initParams->SetDvEnableBonjour(); @@ -445,9 +460,11 @@ OpenHome::Net::Library* ExampleMediaPlayerInit::CreateLibrary(TIpAddress preferr // Check the configuration store for the last subnet joined. try { - Bwn lastSubnetBuf = Bwn((TByte *)&lastSubnet, sizeof(lastSubnet)); - - configStore->Read(Brn(lastSubnetStr), lastSubnetBuf); + if(!TIpAddressUtils::IsZero(lastSubnet)) + { + Bwn lastSubnetBuf = Bwn((TByte *)&lastSubnet, sizeof(lastSubnet)); + configStore->Read(Brn(lastSubnetStr), lastSubnetBuf); + } } catch (StoreKeyNotFound&) { @@ -464,9 +481,10 @@ OpenHome::Net::Library* ExampleMediaPlayerInit::CreateLibrary(TIpAddress preferr { TIpAddress subnet = (*subnetList)[i]->Subnet(); - // If the requested subnet is available, choose it. - const TBool isPreferredSubnet = preferredSubnet.iFamily == kFamilyV4 ? CompareIPv4Addrs(preferredSubnet, subnet) - : CompareIPv6Addrs(preferredSubnet, subnet); + // If the requested subnet is available, choose it + + const TBool isPreferredSubnet = TIpAddressUtils::Equals(preferredSubnet, subnet); + if (isPreferredSubnet) { index = i; @@ -475,8 +493,7 @@ OpenHome::Net::Library* ExampleMediaPlayerInit::CreateLibrary(TIpAddress preferr // If the last used subnet is available, note it. // We'll fall back to it if the requested subnet is not available. - const TBool isLastSubnet = lastSubnet.iFamily == kFamilyV4 ? CompareIPv4Addrs(lastSubnet, subnet) - : CompareIPv6Addrs(lastSubnet, subnet); + const TBool isLastSubnet = TIpAddressUtils::Equals(lastSubnet, subnet); if (isLastSubnet) { @@ -494,25 +511,9 @@ OpenHome::Net::Library* ExampleMediaPlayerInit::CreateLibrary(TIpAddress preferr configStore->Write(Brn(lastSubnetStr), Brn((TByte *)&subnet, sizeof(subnet))); - if (subnet.iFamily == kFamilyV4) - { - Log::Print("Using Subnet %d.%d.%d.%d\n", subnet.iV4 & 0xff, - (subnet.iV4 >> 8) & 0xff, - (subnet.iV4 >> 16) & 0xff, - (subnet.iV4 >> 24) & 0xff); - } - else - { - Log::Print("Using Subnet: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", - subnet.iV6[0], subnet.iV6[1], - subnet.iV6[2], subnet.iV6[3], - subnet.iV6[4], subnet.iV6[5], - subnet.iV6[6], subnet.iV6[7], - subnet.iV6[8], subnet.iV6[9], - subnet.iV6[10], subnet.iV6[11], - subnet.iV6[12], subnet.iV6[13], - subnet.iV6[14], subnet.iV6[15]); - } + Bws addressBuf; + TIpAddressUtils::ToString(subnet, addressBuf); + Log::Print("using subnet %.*s\n", PBUF(addressBuf)); return lib; } diff --git a/linux/ExampleMediaPlayer.h b/linux/ExampleMediaPlayer.h index c0ae707..361416a 100644 --- a/linux/ExampleMediaPlayer.h +++ b/linux/ExampleMediaPlayer.h @@ -38,31 +38,19 @@ namespace Av { class RamStore; class ControlPointProxy; -// Helpers -static TBool CompareIPv4Addrs(const TIpAddress addr1, - const TIpAddress addr2) -{ - return addr1.iFamily == kFamilyV4 - && addr2.iFamily == kFamilyV4 - && addr1.iV4 == addr2.iV4; -} - -static TBool CompareIPv6Addrs(const TIpAddress addr1, - const TIpAddress addr2) -{ - return addr1.iFamily == kFamilyV6 - && addr2.iFamily == kFamilyV6 - && memcmp((TByte*)addr1.iV6[0], (TByte*)addr2.iV6[0], 16) == 0; -} - - - class ExampleMediaPlayer : private Net::IResourceManager { static const Brn kIconOpenHomeFileName; + static const TUint kMinWebUiResourceThreads = 30; //Resource handler count static const TUint kMaxUiTabs = 4; static const TUint kUiSendQueueSize = kMaxUiTabs * 200; + static const TUint kUiMsgBufCount = kUiSendQueueSize + ((kUiSendQueueSize + 1) / 2); + static const TUint kUiMsgBufBytes = 16; + static const TUint kMaxPinsDevice = 6; static const TUint kShellPort = 2323; + static const Brn kResourceDir; + static const Brn kPlayerName; + public: ExampleMediaPlayer(Net::DvStack& aDvStack, Net::CpStack& aCpStack, const Brx& aUdn, @@ -113,9 +101,11 @@ class ExampleMediaPlayer : private Net::IResourceManager Semaphore iSemShutdown; Web::WebAppFramework *iAppFramework; RebootLogger iRebootHandler; + private: Semaphore iDisabled; Av::VolumeControl iVolume; + Media::AudioTimeCpu *iAudioTime; ControlPointProxy *iCpProxy; IOhmTimestamper *iTxTimestamper; IOhmTimestamper *iRxTimestamper; diff --git a/linux/Libav.cpp b/linux/Libav.cpp index 85d570d..71b9957 100644 --- a/linux/Libav.cpp +++ b/linux/Libav.cpp @@ -42,7 +42,7 @@ extern "C" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavformat/avformat.h" -#include "libavresample/avresample.h" +#include } #include "OptionalFeatures.h" @@ -114,8 +114,6 @@ class CodecLibAV : public CodecBase static const TInt32 kInt24Min = -8388608L; static const TInt kDurationRoundUp = 50000; - const TChar *kFmtMp3; - const TChar *kFmtAac; static int avCodecRead(void* ptr, TUint8* buf, TInt buf_size); static TInt64 avCodecSeek(void* ptr, TInt64 offset, TInt whence); @@ -134,9 +132,9 @@ class CodecLibAV : public CodecBase AVFormatContext *iAvFormatCtx; AVCodecContext *iAvCodecContext; TBool iAvPacketCached; - AVPacket iAvPacket; + AVPacket *iAvPacket; AVFrame *iAvFrame; - AVAudioResampleContext *iAvResampleCtx; + SwrContext *iSwrResampleCtx; TInt iStreamId; const TChar *iStreamFormat; TUint iOutputBitDepth; @@ -168,8 +166,6 @@ CodecBase* CodecFactory::NewMp3(IMimeTypeList& aMimeTypeList) CodecLibAV::CodecLibAV(IMimeTypeList& aMimeTypeList) : CodecBase("LIBAV") - , kFmtMp3("Mp3") - , kFmtAac("Aac") , iTotalSamples(0) , iTrackLengthJiffies(0) , iTrackOffset(0) @@ -179,7 +175,7 @@ CodecLibAV::CodecLibAV(IMimeTypeList& aMimeTypeList) , iAvCodecContext(NULL) , iAvPacketCached(false) , iAvFrame(NULL) - , iAvResampleCtx(NULL) + , iSwrResampleCtx(NULL) , iStreamId(-1) , iStreamFormat(NULL) , iOutputBitDepth(0) @@ -203,11 +199,21 @@ CodecLibAV::CodecLibAV(IMimeTypeList& aMimeTypeList) aMimeTypeList.Add("audio/aac"); aMimeTypeList.Add("audio/aacp"); #endif // ENABLE_AAC - + + // av_register_all() got deprecated in lavf 58.9.100 + // It is now useless + // https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L86 + // + #if ( LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,9,100) ) av_register_all(); - + #endif // Initialise our encoded packet container. - av_init_packet(&iAvPacket); + iAvPacket = av_packet_alloc(); + if (iAvPacket == NULL) + { + DBUG_F("audio_decoder_decode_frame: av_packet_alloc failed"); + return; + } } CodecLibAV::~CodecLibAV() @@ -624,50 +630,45 @@ void CodecLibAV::StreamInitialise() #endif // DEBUG // Identify the audio stream. - for (TInt i=0; i<(TInt)iAvFormatCtx->nb_streams; i++) - { - if (iAvFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - { - iStreamId = i; - - switch (iAvFormatCtx->streams[i]->codec->codec_id) - { - case AV_CODEC_ID_AAC: - iStreamFormat = kFmtAac; - break; - case AV_CODEC_ID_MP3: - iStreamFormat = kFmtMp3; - break; - default: - DBUG_F("[CodecLibAV] StreamInitialise - AUDIO FORMAT: " - "UNKNOWN\n"); - break; - } - - break; - } - } - + iStreamId = av_find_best_stream(iAvFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); if (iStreamId == -1) { DBUG_F("[CodecLibAV] StreamInitialise - Could not find Audio Stream\n"); goto failure; } - // Identify and open the correct codec for the audio stream. - AVCodec *codec; + // Disable all other streams + for (TInt i=0; i<(TInt)iAvFormatCtx->nb_streams; i++) + { + if(i!=iStreamId) iAvFormatCtx->streams[i]->discard = AVDISCARD_ALL; + } - iAvCodecContext = iAvFormatCtx->streams[iStreamId]->codec; - codec = avcodec_find_decoder(iAvCodecContext->codec_id); + // Identify and open the correct codec for the audio stream. + AVCodec *codec; + AVCodecParameters *origin_par; + + origin_par = iAvFormatCtx->streams[iStreamId]->codecpar; + codec = avcodec_find_decoder(origin_par->codec_id); if (codec == NULL) { DBUG_F("[CodecLibAV] StreamInitialise - Cannot find codec!\n"); goto failure; } - if (avcodec_open2(iAvCodecContext,codec,NULL) < 0) - { + iAvCodecContext = avcodec_alloc_context3(codec); + if (!iAvCodecContext) { + DBUG_F("[CodecLibAV] StreamInitialise - Can't allocate decoder context\n"); + goto failure; + } + + if (avcodec_parameters_to_context(iAvCodecContext, origin_par) < 0) { + DBUG_F("[CodecLibAV] StreamInitialise - Can't copy decoder context\n"); + goto failure; + } + + if (avcodec_open2(iAvCodecContext,codec,NULL) < 0) + { DBUG_F("[CodecLibAV] StreamInitialise - Codec cannot be opened\n"); goto failure; } @@ -691,9 +692,9 @@ void CodecLibAV::StreamInitialise() // For best playback quality use 'libavresample' to convert this // format to a PCM format we can handle. - iAvResampleCtx = avresample_alloc_context(); + iSwrResampleCtx = swr_alloc(); - if (iAvResampleCtx != NULL) + if (iSwrResampleCtx != NULL) { TInt64 channelLayout = AV_CH_LAYOUT_STEREO; @@ -702,15 +703,15 @@ void CodecLibAV::StreamInitialise() channelLayout = AV_CH_LAYOUT_MONO; } - av_opt_set_int(iAvResampleCtx, "in_channel_layout", + av_opt_set_int(iSwrResampleCtx, "in_channel_layout", channelLayout, 0); - av_opt_set_int(iAvResampleCtx, "out_channel_layout", + av_opt_set_int(iSwrResampleCtx, "out_channel_layout", channelLayout, 0); - av_opt_set_int(iAvResampleCtx, "in_sample_rate", + av_opt_set_int(iSwrResampleCtx, "in_sample_rate", iAvCodecContext->sample_rate, 0); - av_opt_set_int(iAvResampleCtx, "out_sample_rate", + av_opt_set_int(iSwrResampleCtx, "out_sample_rate", iAvCodecContext->sample_rate, 0); - av_opt_set_int(iAvResampleCtx, "in_sample_fmt", + av_opt_set_int(iSwrResampleCtx, "in_sample_fmt", iAvCodecContext->sample_fmt, 0); // Convert to S32P (this will be sampled down manually to 24 @@ -718,10 +719,10 @@ void CodecLibAV::StreamInitialise() iOutputBitDepth = 24; iConvertedFormat = AV_SAMPLE_FMT_S32P; - av_opt_set_int(iAvResampleCtx, "out_sample_fmt", + av_opt_set_int(iSwrResampleCtx, "out_sample_fmt", iConvertedFormat, 0); - if (avresample_open(iAvResampleCtx) < 0) + if (swr_init(iSwrResampleCtx) < 0) { DBUG_F("[CodecLibAV] StreamInitialise - Cannot " "Open Resampler\n"); @@ -777,14 +778,13 @@ void CodecLibAV::StreamInitialise() iOutputBitDepth, iAvCodecContext->sample_rate, iAvCodecContext->channels, - Brn(iStreamFormat), + Brn(codec->name), iTrackLengthJiffies, 0, false, *iSpeakerProfile); - // Create a frame to hold the decoded packets. #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101) iAvFrame = av_frame_alloc(); @@ -813,16 +813,16 @@ void CodecLibAV::StreamCompleted() iFormat = NULL; - if (iAvResampleCtx != NULL) + if (iSwrResampleCtx != NULL) { - avresample_free(&iAvResampleCtx); - iAvResampleCtx = NULL; + swr_free(&iSwrResampleCtx); + iSwrResampleCtx = NULL; } if (iAvPacketCached) { iAvPacketCached = false; - av_free_packet(&iAvPacket); + av_packet_free(&iAvPacket); } if (iAvFrame != NULL) @@ -915,10 +915,15 @@ TBool CodecLibAV::TrySeek(TUint aStreamId, TUint64 aSample) // We attempt to force the issue by executing a read. if (! iSeekExecuted) { - if (av_read_frame(iAvFormatCtx,&iAvPacket) >= 0) + if (av_read_frame(iAvFormatCtx,iAvPacket) >= 0) { iAvPacketCached = true; } + else + { + DBUG_F("[CodecLibAV] av_read_frame problem\n"); + } + if (iSeekSuccess) { @@ -1092,12 +1097,12 @@ void CodecLibAV::processPCM(TUint8 **pcmData, AVSampleFormat fmt, void CodecLibAV::Process() { - TInt frameFinished = 0; TInt plane_size; + TInt ret ; if (! iAvPacketCached) { - if (av_read_frame(iAvFormatCtx,&iAvPacket) < 0) + if (av_read_frame(iAvFormatCtx,iAvPacket) < 0) { #ifdef DEBUG DBUG_F("Info: [CodecLibAV] Process - Frame read error or EOF\n"); @@ -1106,27 +1111,31 @@ void CodecLibAV::Process() THROW(CodecStreamEnded); } } + if (iAvPacket->stream_index != iStreamId) + { + DBUG_F("[CodecLibAV] Process - ERROR: Skip Packet with Stream %d\n",iAvPacket->stream_index); + return; + } iAvPacketCached = false; - if (iAvPacket.stream_index == iStreamId) + ret = avcodec_send_packet(iAvCodecContext, iAvPacket); + if(ret < 0) { - avcodec_decode_audio4(iAvCodecContext, - iAvFrame, - &frameFinished, - &iAvPacket); - - if (! frameFinished) - { - // Couldn't decode a full frame. - // This can happen after seek or on initial switch to radio so - // don't throw an exception. #ifdef DEBUG - DBUG_F("Info: [CodecLibAV] Process - Error Decoding Frame\n"); + DBUG_F("Info: [CodecLibAV] Process - Error Decoding Frame\n"); #endif // DEBUG - av_free_packet(&iAvPacket); + av_packet_free(&iAvPacket); + return; + } + while (ret >= 0) + { + ret = avcodec_receive_frame(iAvCodecContext, iAvFrame); + if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + { + av_packet_free(&iAvPacket); return; } @@ -1141,7 +1150,7 @@ void CodecLibAV::Process() { DBUG_F("ERROR: Cannot obtain frame plane size\n"); - av_free_packet(&iAvPacket); + av_packet_free(&iAvPacket); THROW(CodecStreamCorrupt); } @@ -1164,38 +1173,34 @@ void CodecLibAV::Process() // This should equal the number in the input buffer as the // sample rate is not being modified. outSamples = - avresample_available(iAvResampleCtx) + - av_rescale_rnd(avresample_get_delay(iAvResampleCtx) + - iAvFrame->nb_samples, - iAvCodecContext->sample_rate, - iAvCodecContext->sample_rate, - AV_ROUND_UP); + av_rescale_rnd(swr_get_delay(iSwrResampleCtx, iAvCodecContext->sample_rate) + + iAvFrame->nb_samples, + iAvCodecContext->sample_rate, + iAvCodecContext->sample_rate, + AV_ROUND_UP); // Allocate a buffer for the conversion output. ret = av_samples_alloc((TUint8 **)&convertedData, - &outLinesize, - iAvCodecContext->channels, - outSamples, - iConvertedFormat, - 0); + &outLinesize, + iAvCodecContext->channels, + outSamples, + iConvertedFormat, + 0); if (ret < 0) { DBUG_F("[CodecLibAV] Process - ERROR: Cannot " - "Allocate Sample Conversion Buffer\n"); + "Allocate Sample Conversion Buffer\n"); THROW(CodecStreamEnded); } - - avresample_convert(iAvResampleCtx, - (TUint8 **)&convertedData, - outLinesize, - outSamples, - iAvFrame->extended_data, - plane_size, - iAvFrame->nb_samples); + swr_convert(iSwrResampleCtx, + (TUint8 **)&convertedData, + outSamples, + (const uint8_t**)iAvFrame->extended_data, + iAvFrame->nb_samples); processPCM((TUint8 **)&convertedData, iConvertedFormat, - outLinesize); + outLinesize); av_freep(&convertedData); @@ -1208,7 +1213,7 @@ void CodecLibAV::Process() case AV_SAMPLE_FMT_U8P: { processPCM(iAvFrame->extended_data, iAvCodecContext->sample_fmt, - plane_size); + plane_size); break; } @@ -1219,24 +1224,19 @@ void CodecLibAV::Process() case AV_SAMPLE_FMT_U8: { processPCM(iAvFrame->extended_data, iAvCodecContext->sample_fmt, - iAvFrame->linesize[0]); + iAvFrame->linesize[0]); break; } default: { DBUG_F("[CodecLibAV] Process - ERROR: Format Not " - "Supported Yet\n"); + "Supported Yet\n"); break; } } } - else - { - DBUG_F("[CodecLibAV] Process Unrecognised StreamId [%d], Expected " - "[%d]\n", iAvPacket.stream_index, iStreamId); - } - av_free_packet(&iAvPacket); + av_packet_free(&iAvPacket); if (iStreamStart || iStreamEnded) { diff --git a/linux/Makefile.raspbian b/linux/Makefile.raspbian index 458b0a5..002a243 100644 --- a/linux/Makefile.raspbian +++ b/linux/Makefile.raspbian @@ -73,7 +73,7 @@ endif RESTRICTED_CODECS= ifdef USE_LIBAVCODEC - RESTRICTED_CODECS = -lavresample -lavutil -lavcodec -lavformat + RESTRICTED_CODECS = -lavutil -lavcodec -lavformat -lswresample CFLAGS += -DUSE_LIBAVCODEC else RESTRICTED_CODECS = -lCodecAacFdkAdts -lCodecAacFdk -lCodecAacFdkBase -lCodecMp3 -lCodecAacFdkMp4 diff --git a/linux/Makefile.ubuntu b/linux/Makefile.ubuntu index bc56654..7389e94 100644 --- a/linux/Makefile.ubuntu +++ b/linux/Makefile.ubuntu @@ -84,7 +84,7 @@ endif RESTRICTED_CODECS= ifdef USE_LIBAVCODEC - RESTRICTED_CODECS = -lavresample -lavutil -lavcodec -lavformat + RESTRICTED_CODECS = -lavutil -lavcodec -lavformat -lswresample CFLAGS += -DUSE_LIBAVCODEC else RESTRICTED_CODECS = -lCodecAacFdkMp4 -lCodecAacFdkAdts -lCodecAacFdkBase -lCodecAacFdk -lCodecMp3 diff --git a/linux/MediaPlayerIF.cpp b/linux/MediaPlayerIF.cpp index 2d88d2d..8d184bd 100644 --- a/linux/MediaPlayerIF.cpp +++ b/linux/MediaPlayerIF.cpp @@ -28,6 +28,11 @@ using namespace OpenHome::Configuration; using namespace OpenHome::Media; using namespace OpenHome::Net; +constexpr TIpAddress InitArgs::NO_SUBNET; +constexpr TIpAddress InitArgs::NO_SUBNET_V6; + + + static const TInt TenSeconds = 10; static const TInt FourHours = 4 * 60 * 60; diff --git a/linux/MediaPlayerIF.h b/linux/MediaPlayerIF.h index b4149a3..2c8a7d7 100644 --- a/linux/MediaPlayerIF.h +++ b/linux/MediaPlayerIF.h @@ -13,7 +13,7 @@ typedef struct OpenHome::TBool isCurrent; // Is this the current active subnet } SubnetRecord; -typedef struct InitArgsStruct +typedef struct InitArgs { static constexpr TIpAddress NO_SUBNET = { diff --git a/linux/OpenHomePlayer.cpp b/linux/OpenHomePlayer.cpp index d66eace..d3f24f9 100644 --- a/linux/OpenHomePlayer.cpp +++ b/linux/OpenHomePlayer.cpp @@ -463,7 +463,7 @@ int main(int argc, char **argv) } g_mPlayerArgs.restarted = false; - g_mPlayerArgs.subnet = InitArgs::NO_SUBNET; + g_mPlayerArgs.subnet = TIpAddress(); // Validate the format of any supplied subnet. if (argc == 2) diff --git a/linux/OptionalFeatures.h b/linux/OptionalFeatures.h index 6860614..3347105 100644 --- a/linux/OptionalFeatures.h +++ b/linux/OptionalFeatures.h @@ -1,23 +1,28 @@ // Optional Features -// Uncomment this line to enable MP3 support -//#define ENABLE_MP3 +#ifndef HEADER_OPTIONAL_FEATURES +#define HEADER_OPTIONAL_FEATURES +// Uncomment this line to enable MP3 support +// #define ENABLE_MP3 // Uncomment this line to enable AAC support -//#define ENABLE_AAC - +// #define ENABLE_AAC // Uncomment this line to enable the Radio source -//#define ENABLE_RADIO -#define TUNEIN_PARTNER_ID TUNEIN_PARTNER_ID_STRING - +// #define ENABLE_RADIO // Uncomment this line to enable Tidal service support -//#define ENABLE_TIDAL -// Replace TIDAL_TOKEN_STRING with a valid Tidal token -#define TIDAL_TOKEN TIDAL_TOKEN_STRING - +// #define ENABLE_TIDAL // Uncomment this line to enable Qobuz service support -//#define ENABLE_QOBUZ +// #define ENABLE_QOBUZ + + +static const OpenHome::Brn TuneinAuthPartnerId(""); +// Replace TIDAL_TOKEN_STRING with a valid Tidal token +static const OpenHome::Brn TildaAuthAppId(""); +static const OpenHome::Brn TildaAuthClientId(""); +static const OpenHome::Brn TildaAuthClientSecret(""); // Replace QOBUZ_APPID_STRING with a valid Qobuz Application ID -#define QOBUZ_APPID QOBUZ_APPID_STRING +static const OpenHome::Brn QoubusAuthClientId(""); // Replace QOBUZ_SECRET_STRING with a valid Qobuz secret -#define QOBUZ_SECRET QOBUZ_SECRET_STRING +static const OpenHome::Brn QoubusAuthClientSecret(""); + +#endif // HEADER_OPTIONAL_FEATURES diff --git a/linux/RamStore.cpp b/linux/RamStore.cpp index 1c89186..10f6abd 100644 --- a/linux/RamStore.cpp +++ b/linux/RamStore.cpp @@ -21,4 +21,5 @@ void RamStore::LoadStaticData(IStoreLoaderStatic& aLoader) aLoader.AddStaticItem(StaticDataKey::kBufModelInfo, "Example implementation of ohMediaPlayer"); aLoader.AddStaticItem(StaticDataKey::kBufModelUrl, "http://www.openhome.org/wiki/OhMedia"); aLoader.AddStaticItem(StaticDataKey::kBufModelImageUrl, iImageFileName.CString()); + aLoader.AddStaticItem(StaticDataKey::kBufModelImageHiresUrl, iImageFileName.CString()); } diff --git a/linux/Volume.cpp b/linux/Volume.cpp index 7ac4ca7..30815ff 100644 --- a/linux/Volume.cpp +++ b/linux/Volume.cpp @@ -105,7 +105,7 @@ VolumeControl::VolumeControl() iElem = snd_mixer_find_selem(iHandle, iSid); // Quit the loop if control found. - if (iElem > NULL) + if (IsVolumeSupported()) { break; } @@ -177,9 +177,19 @@ void VolumeControl::SetVolume(TUint aVolume) return; } -void VolumeControl::SetBalance(TInt /*aBalance*/) +void VolumeControl::SetBalance(TInt aBalance) { - // Not Implemented + long left, right; + // Sanity Check + if (! IsVolumeSupported()) + { + return; + } + snd_mixer_selem_get_playback_dB(iElem, SND_MIXER_SCHN_FRONT_LEFT,&left); + snd_mixer_selem_get_playback_dB(iElem, SND_MIXER_SCHN_FRONT_RIGHT, &right); + + snd_mixer_selem_set_playback_dB(iElem, SND_MIXER_SCHN_FRONT_LEFT, 0.25*left, 0); + snd_mixer_selem_set_playback_dB(iElem, SND_MIXER_SCHN_FRONT_RIGHT, 0.75*right, 0); } void VolumeControl::SetFade(TInt /*aFade*/) diff --git a/projectdata/dependencies.json b/projectdata/dependencies.json index 0295886..2dd4987 100644 --- a/projectdata/dependencies.json +++ b/projectdata/dependencies.json @@ -2,7 +2,7 @@ { "name": "ohNet", "type": "openhome", "platform-specific": true, - "version": "1.32.4341", + "version": "1.37.5491", "archive-suffix": "-${debugmode}", "main-dir": "${dest}${name}-${platform}-${debugmode}", "configure-args": [ @@ -14,7 +14,7 @@ { "name": "ohWafHelpers", "type": "openhome", "platform-specific": false, - "version": "0.0.115", + "version": "0.2.144", "archive-filename": "${name}-${version}.tar.gz", "source-git": "https://github.com/openhome/ohWafHelpers.git" }, @@ -27,17 +27,15 @@ { "name": "ohMediaPlayer", "type": "openhome", "platform-specific": true, - "version": "1.135.984", + "version": "1.157.1168", "archive-suffix": "-${debugmode}", "source-git": "https://github.com/openhome/LitePipe.git" }, { "name": "ohNetGenerated", "type": "openhome", "platform-specific": true, - "version": "1.1.195", + "version": "1.1.229", "archive-filename": "${name}-${version}-${archive-platform}-${debugmode}.tar.gz", "source-git": "https://github.com/openhome/ohNetGenerated.git" } -] - - +] \ No newline at end of file