Skip to content
This repository

Dirty audio #1138

Merged
merged 3 commits into from almost 2 years ago

1 participant

Cory Fields
Cory Fields
Owner
theuni commented

This work comes from @jmarshallnz, I'm just the PR monkey.

  1. Don't have AE constantly converting and otherwise wasting resources when there is no sound output. Saves a boatload of cpu usage on embedded platforms.
  2. Pass the status from 1 down to the sinks, so that they can choose to be smarter when there's nothing to do.

Note that for 2, we don't actually change any sink behaviors, only give them the knowledge of whether the buffer contains silence or real audio. Some sinks may be able to do nothing, while others may have to keep silence flowing. I'll leave that to the various platform devs.

Cory Fields and others added some commits
Cory Fields theuni merged commit c1cecb9 into from
Cory Fields theuni closed this
Tobias Hieta tru referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Tobias Hieta tru referenced this pull request from a commit in RasPlex/plex-home-theatre
Tobias Hieta tru Added warning dialog for when user will clear a modified PlayQueue
Fixes #1138
3874365
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 2 authors.

Jul 11, 2012
Cory Fields [SoftAE] pass audio/silence down to the sink so it can decide if it w…
…ants to output
74ba6a5
Jonathan Marshall [SoftAE] change RunOutputStage to take in a boolean for audio (vs sil…
…ence) and to return the number of samples taken by the output stage
f5a89c1
Jonathan Marshall [SoftAE] don't process silence when we don't have to. ff3a880
This page is out of date. Refresh to see the latest.
51 xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
@@ -854,11 +854,13 @@ void CSoftAE::Run()
854 854 CSingleLock runningLock(m_runningLock);
855 855 CLog::Log(LOGINFO, "CSoftAE::Run - Thread Started");
856 856
  857 + bool hasAudio = false;
857 858 while (m_running)
858 859 {
859 860 bool restart = false;
860 861
861   - (this->*m_outputStageFn)();
  862 + if ((this->*m_outputStageFn)(hasAudio) > 0)
  863 + hasAudio = false; /* taken some audio - reset our silence flag */
862 864
863 865 /* if we have enough room in the buffer */
864 866 if (m_buffer.Free() >= m_frameSize)
@@ -869,7 +871,8 @@ void CSoftAE::Run()
869 871
870 872 /* run the stream stage */
871 873 CSoftAEStream *oldMaster = m_masterStream;
872   - (this->*m_streamStageFn)(m_chLayout.Count(), out, restart);
  874 + if ((this->*m_streamStageFn)(m_chLayout.Count(), out, restart) > 0)
  875 + hasAudio = true; /* have some audio */
873 876
874 877 /* if in audiophile mode and the master stream has changed, flag for restart */
875 878 if (m_audiophile && oldMaster != m_masterStream)
@@ -895,10 +898,11 @@ void CSoftAE::AllocateConvIfNeeded(size_t convertedSize)
895 898 }
896 899 }
897 900
898   -void CSoftAE::MixSounds(float *buffer, unsigned int samples)
  901 +unsigned int CSoftAE::MixSounds(float *buffer, unsigned int samples)
899 902 {
900 903 SoundStateList::iterator itt;
901 904
  905 + unsigned int mixed = 0;
902 906 CSingleLock lock(m_soundSampleLock);
903 907 for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
904 908 {
@@ -926,18 +930,24 @@ void CSoftAE::MixSounds(float *buffer, unsigned int samples)
926 930 ss->samples += mixSamples;
927 931
928 932 ++itt;
  933 + ++mixed;
929 934 }
  935 + return mixed;
930 936 }
931 937
932   -void CSoftAE::FinalizeSamples(float *buffer, unsigned int samples)
  938 +bool CSoftAE::FinalizeSamples(float *buffer, unsigned int samples, bool hasAudio)
933 939 {
934 940 if (m_soundMode != AE_SOUND_OFF)
935   - MixSounds(buffer, samples);
  941 + hasAudio |= MixSounds(buffer, samples) > 0;
  942 +
  943 + /* no need to process if we don't have audio (buffer is memset to 0) */
  944 + if (!hasAudio)
  945 + return false;
936 946
937 947 if (m_muted)
938 948 {
939 949 memset(buffer, 0, samples * sizeof(float));
940   - return;
  950 + return false;
941 951 }
942 952
943 953 /* deamplify */
@@ -973,21 +983,22 @@ void CSoftAE::FinalizeSamples(float *buffer, unsigned int samples)
973 983
974 984 /* if there were no samples outside of the range, dont clamp the buffer */
975 985 if (!clamp)
976   - return;
  986 + return true;
977 987
978 988 CLog::Log(LOGDEBUG, "CSoftAE::FinalizeSamples - Clamping buffer of %d samples", samples);
979 989 CAEUtil::ClampArray(buffer, samples);
  990 + return true;
980 991 }
981 992
982   -void CSoftAE::RunOutputStage()
  993 +int CSoftAE::RunOutputStage(bool hasAudio)
983 994 {
984 995 const unsigned int needSamples = m_sinkFormat.m_frames * m_sinkFormat.m_channelLayout.Count();
985 996 const size_t needBytes = needSamples * sizeof(float);
986 997 if (m_buffer.Used() < needBytes)
987   - return;
  998 + return 0;
988 999
989 1000 void *data = m_buffer.Raw(needBytes);
990   - FinalizeSamples((float*)data, needSamples);
  1001 + hasAudio = FinalizeSamples((float*)data, needSamples, hasAudio);
991 1002
992 1003 int wroteFrames;
993 1004 if (m_convertFn)
@@ -998,7 +1009,7 @@ void CSoftAE::RunOutputStage()
998 1009 data = m_converted;
999 1010 }
1000 1011
1001   - wroteFrames = m_sink->AddPackets((uint8_t*)data, m_sinkFormat.m_frames);
  1012 + wroteFrames = m_sink->AddPackets((uint8_t*)data, m_sinkFormat.m_frames, hasAudio);
1002 1013
1003 1014 /* Return value of INT_MAX signals error in sink - restart */
1004 1015 if (wroteFrames == INT_MAX)
@@ -1009,12 +1020,13 @@ void CSoftAE::RunOutputStage()
1009 1020 }
1010 1021
1011 1022 m_buffer.Shift(NULL, wroteFrames * m_sinkFormat.m_channelLayout.Count() * sizeof(float));
  1023 + return wroteFrames;
1012 1024 }
1013 1025
1014   -void CSoftAE::RunRawOutputStage()
  1026 +int CSoftAE::RunRawOutputStage(bool hasAudio)
1015 1027 {
1016 1028 if(m_buffer.Used() < m_sinkBlockSize)
1017   - return;
  1029 + return 0;
1018 1030
1019 1031 void *data = m_buffer.Raw(m_sinkBlockSize);
1020 1032
@@ -1035,7 +1047,7 @@ void CSoftAE::RunRawOutputStage()
1035 1047 data = m_converted;
1036 1048 }
1037 1049
1038   - int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames);
  1050 + int wroteFrames = m_sink->AddPackets((uint8_t *)data, m_sinkFormat.m_frames, hasAudio);
1039 1051
1040 1052 /* Return value of INT_MAX signals error in sink - restart */
1041 1053 if (wroteFrames == INT_MAX)
@@ -1046,17 +1058,19 @@ void CSoftAE::RunRawOutputStage()
1046 1058 }
1047 1059
1048 1060 m_buffer.Shift(NULL, wroteFrames * m_sinkFormat.m_frameSize);
  1061 + return wroteFrames;
1049 1062 }
1050 1063
1051   -void CSoftAE::RunTranscodeStage()
  1064 +int CSoftAE::RunTranscodeStage(bool hasAudio)
1052 1065 {
1053 1066 /* if we dont have enough samples to encode yet, return */
1054 1067 unsigned int block = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize;
1055 1068 unsigned int sinkBlock = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
1056 1069
  1070 + int encodedFrames = 0;
1057 1071 if (m_buffer.Used() >= block && m_encodedBuffer.Used() < sinkBlock * 2)
1058 1072 {
1059   - FinalizeSamples((float*)m_buffer.Raw(block), m_encoderFormat.m_frameSamples);
  1073 + hasAudio = FinalizeSamples((float*)m_buffer.Raw(block), m_encoderFormat.m_frameSamples, hasAudio);
1060 1074
1061 1075 void *buffer;
1062 1076 if (m_convertFn)
@@ -1078,7 +1092,7 @@ void CSoftAE::RunTranscodeStage()
1078 1092 else
1079 1093 buffer = m_buffer.Raw(block);
1080 1094
1081   - int encodedFrames = m_encoder->Encode((float*)buffer, m_encoderFormat.m_frames);
  1095 + encodedFrames = m_encoder->Encode((float*)buffer, m_encoderFormat.m_frames);
1082 1096 m_buffer.Shift(NULL, encodedFrames * m_encoderFormat.m_frameSize);
1083 1097
1084 1098 uint8_t *packet;
@@ -1094,7 +1108,7 @@ void CSoftAE::RunTranscodeStage()
1094 1108 /* if we have enough data to write */
1095 1109 if (m_encodedBuffer.Used() >= sinkBlock)
1096 1110 {
1097   - int wroteFrames = m_sink->AddPackets((uint8_t*)m_encodedBuffer.Raw(sinkBlock), m_sinkFormat.m_frames);
  1111 + int wroteFrames = m_sink->AddPackets((uint8_t*)m_encodedBuffer.Raw(sinkBlock), m_sinkFormat.m_frames, hasAudio);
1098 1112
1099 1113 /* Return value of INT_MAX signals error in sink - restart */
1100 1114 if (wroteFrames == INT_MAX)
@@ -1106,6 +1120,7 @@ void CSoftAE::RunTranscodeStage()
1106 1120
1107 1121 m_encodedBuffer.Shift(NULL, wroteFrames * m_sinkFormat.m_frameSize);
1108 1122 }
  1123 + return encodedFrames;
1109 1124 }
1110 1125
1111 1126 unsigned int CSoftAE::RunRawStreamStage(unsigned int channelCount, void *out, bool &restart)
32 xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
@@ -195,15 +195,35 @@ class CSoftAE : public IThreadedAE
195 195 void AllocateConvIfNeeded(size_t convertedSize);
196 196
197 197 /* thread run stages */
198   - void MixSounds (float *buffer, unsigned int samples);
199   - void FinalizeSamples (float *buffer, unsigned int samples);
  198 +
  199 + /*! \brief Mix UI sounds into the current stream.
  200 + \param buffer the buffer to mix into.
  201 + \param samples the number of samples in the buffer.
  202 + \return the number of sounds mixed into the buffer.
  203 + */
  204 + unsigned int MixSounds (float *buffer, unsigned int samples);
  205 +
  206 + /*! \brief Finalize samples ready for sending to the output device.
  207 + Mixes in any UI sounds, applies volume adjustment, and clamps to [-1,1].
  208 + \param buffer the audio data.
  209 + \param samples the number of samples in the buffer.
  210 + \param hasAudio whether we have audio from a stream (true) or silence (false)
  211 + \return true if we have audio to output, false if we have only silence.
  212 + */
  213 + bool FinalizeSamples (float *buffer, unsigned int samples, bool hasAudio);
200 214
201 215 CSoftAEStream *m_masterStream;
202 216
203   - void (CSoftAE::*m_outputStageFn)();
204   - void RunOutputStage ();
205   - void RunRawOutputStage();
206   - void RunTranscodeStage();
  217 + /*! \brief Run the output stage on the audio.
  218 + Prepares streamed data, mixes in any UI sounds, converts to a format suitable
  219 + for the sink, then outputs to the sink.
  220 + \param hasAudio whether or not we have audio (true) or silence (false).
  221 + \return the number of samples sent to the sink.
  222 + */
  223 + int (CSoftAE::*m_outputStageFn)(bool);
  224 + int RunOutputStage (bool hasAudio);
  225 + int RunRawOutputStage(bool hasAudio);
  226 + int RunTranscodeStage(bool hasAudio);
207 227
208 228 unsigned int (CSoftAE::*m_streamStageFn)(unsigned int channelCount, void *out, bool &restart);
209 229 unsigned int RunRawStreamStage (unsigned int channelCount, void *out, bool &restart);
2  xbmc/cores/AudioEngine/Interfaces/AESink.h
@@ -72,7 +72,7 @@ class IAESink
72 72 /*
73 73 Adds packets to be sent out, this routine MUST block or sleep.
74 74 */
75   - virtual unsigned int AddPackets(uint8_t *data, unsigned int frames) = 0;
  75 + virtual unsigned int AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) = 0;
76 76
77 77 /*
78 78 Drain the sink
2  xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -474,7 +474,7 @@ double CAESinkALSA::GetCacheTotal()
474 474 return (double)m_bufferSize * m_formatSampleRateMul;
475 475 }
476 476
477   -unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames)
  477 +unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
478 478 {
479 479 if (!m_pcm)
480 480 return 0;
2  xbmc/cores/AudioEngine/Sinks/AESinkALSA.h
@@ -48,7 +48,7 @@ class CAESinkALSA : public IAESink
48 48 virtual double GetDelay ();
49 49 virtual double GetCacheTime ();
50 50 virtual double GetCacheTotal ();
51   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  51 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
52 52 virtual void Drain ();
53 53
54 54 static void EnumerateDevicesEx(AEDeviceInfoList &list);
2  xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h
@@ -43,7 +43,7 @@ class CAESinkDirectSound : public IAESink
43 43 virtual double GetDelay ();
44 44 virtual double GetCacheTime ();
45 45 virtual double GetCacheTotal ();
46   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  46 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
47 47 static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
48 48 private:
49 49 void AEChannelsFromSpeakerMask(DWORD speakers);
2  xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp
@@ -81,7 +81,7 @@ double CAESinkNULL::GetDelay()
81 81 return std::max(0.0, (double)(m_ts - CurrentHostCounter()) / 1000000.0f);
82 82 }
83 83
84   -unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames)
  84 +unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
85 85 {
86 86 float timeout = m_msPerFrame * frames;
87 87 m_ts = CurrentHostCounter() + MathUtils::round_int(timeout * 1000000.0f);
2  xbmc/cores/AudioEngine/Sinks/AESinkNULL.h
@@ -40,7 +40,7 @@ class CAESinkNULL : public IAESink
40 40 virtual double GetDelay ();
41 41 virtual double GetCacheTime () { return 0.0; }
42 42 virtual double GetCacheTotal () { return 0.0; }
43   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  43 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
44 44 virtual void Drain ();
45 45 static void EnumerateDevices(AEDeviceList &devices, bool passthrough);
46 46 private:
2  xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp
@@ -427,7 +427,7 @@ double CAESinkOSS::GetDelay()
427 427 return (double)delay / (m_format.m_frameSize * m_format.m_sampleRate);
428 428 }
429 429
430   -unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames)
  430 +unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
431 431 {
432 432 int size = frames * m_format.m_frameSize;
433 433 int wrote = write(m_fd, data, size);
2  xbmc/cores/AudioEngine/Sinks/AESinkOSS.h
@@ -42,7 +42,7 @@ class CAESinkOSS : public IAESink
42 42 virtual double GetDelay ();
43 43 virtual double GetCacheTime () { return 0.0; } /* FIXME */
44 44 virtual double GetCacheTotal () { return 0.0; } /* FIXME */
45   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  45 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
46 46 virtual void Drain ();
47 47 static void EnumerateDevicesEx(AEDeviceInfoList &list);
48 48 private:
2  xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp
@@ -73,7 +73,7 @@ double CAESinkProfiler::GetDelay()
73 73 return 0.0f;
74 74 }
75 75
76   -unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames)
  76 +unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
77 77 {
78 78 int64_t ts = CurrentHostCounter();
79 79 CLog::Log(LOGDEBUG, "CAESinkProfiler::AddPackets - latency %f ms", (float)(ts - m_ts) / 1000000.0f);
2  xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h
@@ -40,7 +40,7 @@ class CAESinkProfiler : public IAESink
40 40 virtual double GetDelay ();
41 41 virtual double GetCacheTime () { return 0.0; }
42 42 virtual double GetCacheTotal () { return 0.0; }
43   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  43 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
44 44 virtual void Drain ();
45 45 static void EnumerateDevices(AEDeviceList &devices, bool passthrough);
46 46 private:
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -362,7 +362,7 @@ double CAESinkWASAPI::GetCacheTotal()
362 362 return hnsLatency / 10.0;
363 363 }
364 364
365   -unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames)
  365 +unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
366 366 {
367 367 if (!m_initialized)
368 368 return 0;
2  xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h
@@ -43,7 +43,7 @@ class CAESinkWASAPI : public IAESink
43 43 virtual double GetDelay ();
44 44 virtual double GetCacheTime ();
45 45 virtual double GetCacheTotal ();
46   - virtual unsigned int AddPackets (uint8_t *data, unsigned int frames);
  46 + virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio);
47 47 static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList);
48 48 private:
49 49 bool InitializeExclusive(AEAudioFormat &format);

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.