Skip to content

Commit

Permalink
[application] Fix a race condition on CApplicationPlayerCallback::m_i…
Browse files Browse the repository at this point in the history
…temCurrentFile

* There's a possibility of a race codition on CApplicationPlayerCallback::m_itemCurrentFile
  leading to heap-use-after-free reported by the address sanitizer [1].

* The crash happens when GUI_MSG_UPDATE_ITEM is being handled.
  CApplicationPlayerCallback::m_itemCurrentFile can be accessed
  concurrently by the main thread in CApplication::OnMessage
  and CApplicationPlayerCallback::OnPlayBackStarted in the video thread.

  Sometimes CApplicationPlayerCallback::OnPlayBackStarted is called first,
  resets the m_itemCurrentFile (and deallocates the object). Then
  CApplication::OnMessage tries to read it - this is where
  heap-use-after-free occurs.

* In order to mitigate the issue introduce additional messages
  GUI_MSG_PLAYBACK_PAUSED, GUI_MSG_PLAYBACK_RESUMED, GUI_MSG_PLAYBACK_PAUSED
  and GUI_MSG_PLAYBACK_SPEED_CHANGED. Those messages are sent from the GUI
  thread to the main thread. That way the access to
  CApplicationPlayerCallback::m_itemCurrentFile is serialized (it will be
  accessed only from the main thread).

* Fixes xbmc#23247.

[1]:
=================================================================
==34632==ERROR: AddressSanitizer: heap-use-after-free on address 0x6070000ea040 at pc 0x7ff0eba5f427 bp 0x7ffc508e6f90 sp 0x7ffc508e6738
WRITE of size 65 at 0x6070000ea040 thread T0
    #0 0x7ff0eba5f426 in __interceptor_memcpy /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
    xbmc#1 0x7ff0ea8b1135 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (/usr/lib/libtinyxml.so.0+0xf135)
    xbmc#2 0x7ff0e914c49d in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1571
    xbmc#3 0x7ff0e914c49d in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:805
    xbmc#4 0x55bf362b423b in CFileItem::SetDynPath(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/dobo/kodi/xbmc/xbmc/FileItem.cpp:2021
    xbmc#5 0x55bf362af7bb in CFileItem::UpdateInfo(CFileItem const&, bool) /home/dobo/kodi/xbmc/xbmc/FileItem.cpp:1741
    xbmc#6 0x55bf35d56d30 in CApplication::OnMessage(CGUIMessage&) /home/dobo/kodi/xbmc/xbmc/application/Application.cpp:2727
    xbmc#7 0x55bf35b590ba in CGUIWindowManager::SendMessage(CGUIMessage&) /home/dobo/kodi/xbmc/xbmc/guilib/GUIWindowManager.cpp:499
    xbmc#8 0x55bf35b65e30 in CGUIWindowManager::DispatchThreadMessages() /home/dobo/kodi/xbmc/xbmc/guilib/GUIWindowManager.cpp:1561
    xbmc#9 0x55bf35d5bfe2 in CApplication::Process() /home/dobo/kodi/xbmc/xbmc/application/Application.cpp:3100
    xbmc#10 0x55bf35d4c2e0 in CApplication::Run() /home/dobo/kodi/xbmc/xbmc/application/Application.cpp:1907
    xbmc#11 0x55bf356ae727 in XBMC_Run /home/dobo/kodi/xbmc/xbmc/platform/xbmc.cpp:61
    xbmc#12 0x55bf34321830 in main /home/dobo/kodi/xbmc/xbmc/platform/posix/main.cpp:71
    xbmc#13 0x7ff0e9c9a78f  (/usr/lib/libc.so.6+0x2378f)
    xbmc#14 0x7ff0e9c9a849 in __libc_start_main (/usr/lib/libc.so.6+0x23849)
    xbmc#15 0x55bf343213d4 in _start (/usr/lib/kodi/kodi.bin+0x2c263d4)

0x6070000ea040 is located 0 bytes inside of 66-byte region [0x6070000ea040,0x6070000ea082)
freed by thread T62 here:
    #0 0x7ff0ebac11fa in operator delete(void*) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:152
    xbmc#1 0x55bf3629cc1b in CFileItem::~CFileItem() /home/dobo/kodi/xbmc/xbmc/FileItem.cpp:439
    xbmc#2 0x55bf3629ccbb in CFileItem::~CFileItem() /home/dobo/kodi/xbmc/xbmc/FileItem.cpp:439
    xbmc#3 0x55bf3440220d in std::_Sp_counted_ptr<CFileItem*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/12.2.1/bits/shared_ptr_base.h:428
    xbmc#4 0x55bf34321add in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/12.2.1/bits/shared_ptr_base.h:346
    xbmc#5 0x55bf34321e57 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/12.2.1/bits/shared_ptr_base.h:1071
    xbmc#6 0x55bf343f1309 in std::__shared_ptr<CFileItem, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/12.2.1/bits/shared_ptr_base.h:1524
    xbmc#7 0x55bf343f65f6 in std::enable_if<std::__sp_is_constructible<CFileItem, CFileItem>::value, void>::type std::__shared_ptr<CFileItem, (__gnu_cxx::_Lock_policy)2>::reset<CFileItem>(CFileItem*) (/usr/lib/kodi/kodi.bin+0x2cfb5f6)
    xbmc#8 0x55bf35da0e50 in CApplicationPlayerCallback::OnPlayBackStarted(CFileItem const&) /home/dobo/kodi/xbmc/xbmc/application/ApplicationPlayerCallback.cpp:84
    xbmc#9 0x55bf34dbd001 in operator() /home/dobo/kodi/xbmc/xbmc/cores/VideoPlayer/VideoPlayer.cpp:2631
    xbmc#10 0x55bf34de836b in DoWork /home/dobo/kodi/xbmc/xbmc/utils/JobManager.h:39
    xbmc#11 0x55bf35422489 in CJobWorker::Process() /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:55
    xbmc#12 0x55bf35608346 in CThread::Action() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:267
    xbmc#13 0x55bf35606c3c in operator() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:138
    xbmc#14 0x55bf35608dd0 in __invoke_impl<void, CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:61
    xbmc#15 0x55bf35608c89 in __invoke<CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:96
    xbmc#16 0x55bf35608bbc in _M_invoke<0, 1, 2> /usr/include/c++/12.2.1/bits/std_thread.h:258
    xbmc#17 0x55bf35608b59 in operator() /usr/include/c++/12.2.1/bits/std_thread.h:265
    xbmc#18 0x55bf35608b3d in _M_run /usr/include/c++/12.2.1/bits/std_thread.h:210
    xbmc#19 0x7ff0e90d72c2 in execute_native_thread_routine /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:82

previously allocated by thread T62 here:
    #0 0x7ff0ebac0672 in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:95
    xbmc#1 0x7ff0ea8b10fb in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (/usr/lib/libtinyxml.so.0+0xf0fb)

Thread T62 created by T46 here:
    #0 0x7ff0eba64207 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:207
    xbmc#1 0x7ff0e90d73a9 in __gthread_create /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
    xbmc#2 0x7ff0e90d73a9 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:147
    xbmc#3 0x55bf356077d6 in CThread::Create(bool) /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:159
    xbmc#4 0x55bf354221c2 in CJobWorker::CJobWorker(CJobManager*) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:32
    xbmc#5 0x55bf354261d2 in CJobManager::StartWorkers(CJob::PRIORITY) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:288
    xbmc#6 0x55bf35425693 in CJobManager::AddJob(CJob*, IJobCallback*, CJob::PRIORITY) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:247
    xbmc#7 0x55bf3542406d in CJobQueue::QueueNextJob() /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:147
    xbmc#8 0x55bf354239ed in CJobQueue::AddJob(CJob*) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:124
    xbmc#9 0x55bf368a363b in void CJobQueue::Submit<CEventSource<PVR::PVREvent>::Publish<PVR::PVREvent>(PVR::PVREvent)::{lambda()xbmc#1}>(CEventSource<PVR::PVREvent>::Publish<PVR::PVREvent>(PVR::PVREvent)::{lambda()xbmc#1}&&) (/usr/lib/kodi/kodi.bin+0x51a863b)
    xbmc#10 0x55bf368a0d18 in void CEventSource<PVR::PVREvent>::Publish<PVR::PVREvent>(PVR::PVREvent) /home/dobo/kodi/xbmc/xbmc/utils/EventStream.h:80
    xbmc#11 0x55bf3689b4db in PVR::CPVREpgContainer::UpdateEPG(bool) /home/dobo/kodi/xbmc/xbmc/pvr/epg/EpgContainer.cpp:805
    xbmc#12 0x55bf36894d13 in PVR::CPVREpgContainer::Process() /home/dobo/kodi/xbmc/xbmc/pvr/epg/EpgContainer.cpp:346
    xbmc#13 0x55bf35608346 in CThread::Action() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:267
    xbmc#14 0x55bf35606c3c in operator() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:138
    xbmc#15 0x55bf35608dd0 in __invoke_impl<void, CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:61
    xbmc#16 0x55bf35608c89 in __invoke<CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:96
    xbmc#17 0x55bf35608bbc in _M_invoke<0, 1, 2> /usr/include/c++/12.2.1/bits/std_thread.h:258
    xbmc#18 0x55bf35608b59 in operator() /usr/include/c++/12.2.1/bits/std_thread.h:265
    xbmc#19 0x55bf35608b3d in _M_run /usr/include/c++/12.2.1/bits/std_thread.h:210
    xbmc#20 0x7ff0e90d72c2 in execute_native_thread_routine /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:82

Thread T46 created by T43 here:
    #0 0x7ff0eba64207 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:207
    xbmc#1 0x7ff0e90d73a9 in __gthread_create /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
    xbmc#2 0x7ff0e90d73a9 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:147
    xbmc#3 0x55bf356077d6 in CThread::Create(bool) /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:159
    xbmc#4 0x55bf36892a8a in PVR::CPVREpgContainer::Start() /home/dobo/kodi/xbmc/xbmc/pvr/epg/EpgContainer.cpp:153
    xbmc#5 0x55bf36b1ae80 in PVR::CPVRManager::Process() /home/dobo/kodi/xbmc/xbmc/pvr/PVRManager.cpp:513
    xbmc#6 0x55bf35608346 in CThread::Action() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:267
    xbmc#7 0x55bf35606c3c in operator() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:138
    xbmc#8 0x55bf35608dd0 in __invoke_impl<void, CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:61
    xbmc#9 0x55bf35608c89 in __invoke<CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:96
    xbmc#10 0x55bf35608bbc in _M_invoke<0, 1, 2> /usr/include/c++/12.2.1/bits/std_thread.h:258
    xbmc#11 0x55bf35608b59 in operator() /usr/include/c++/12.2.1/bits/std_thread.h:265
    xbmc#12 0x55bf35608b3d in _M_run /usr/include/c++/12.2.1/bits/std_thread.h:210
    xbmc#13 0x7ff0e90d72c2 in execute_native_thread_routine /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:82

Thread T43 created by T24 here:
    #0 0x7ff0eba64207 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:207
    xbmc#1 0x7ff0e90d73a9 in __gthread_create /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
    xbmc#2 0x7ff0e90d73a9 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:147
    xbmc#3 0x55bf356077d6 in CThread::Create(bool) /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:159
    xbmc#4 0x55bf36b1a1f6 in PVR::CPVRManager::Start() /home/dobo/kodi/xbmc/xbmc/pvr/PVRManager.cpp:388
    xbmc#5 0x55bf36a80919 in PVR::CPVRClients::UpdateClients(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int) /home/dobo/kodi/xbmc/xbmc/pvr/addons/PVRClients.cpp:212
    xbmc#6 0x55bf36a7e4e8 in PVR::CPVRClients::Start() /home/dobo/kodi/xbmc/xbmc/pvr/addons/PVRClients.cpp:59
    xbmc#7 0x55bf36b19e06 in operator() /home/dobo/kodi/xbmc/xbmc/pvr/PVRManager.cpp:362
    xbmc#8 0x55bf36b2c143 in DoWork /home/dobo/kodi/xbmc/xbmc/utils/JobManager.h:39
    xbmc#9 0x55bf35422489 in CJobWorker::Process() /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:55
    xbmc#10 0x55bf35608346 in CThread::Action() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:267
    xbmc#11 0x55bf35606c3c in operator() /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:138
    xbmc#12 0x55bf35608dd0 in __invoke_impl<void, CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:61
    xbmc#13 0x55bf35608c89 in __invoke<CThread::Create(bool)::<lambda(CThread*, std::promise<bool>)>, CThread*, std::promise<bool> > /usr/include/c++/12.2.1/bits/invoke.h:96
    xbmc#14 0x55bf35608bbc in _M_invoke<0, 1, 2> /usr/include/c++/12.2.1/bits/std_thread.h:258
    xbmc#15 0x55bf35608b59 in operator() /usr/include/c++/12.2.1/bits/std_thread.h:265
    xbmc#16 0x55bf35608b3d in _M_run /usr/include/c++/12.2.1/bits/std_thread.h:210
    xbmc#17 0x7ff0e90d72c2 in execute_native_thread_routine /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:82

Thread T24 created by T0 here:
    #0 0x7ff0eba64207 in __interceptor_pthread_create /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_interceptors.cpp:207
    xbmc#1 0x7ff0e90d73a9 in __gthread_create /usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
    xbmc#2 0x7ff0e90d73a9 in std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/thread.cc:147
    xbmc#3 0x55bf356077d6 in CThread::Create(bool) /home/dobo/kodi/xbmc/xbmc/threads/Thread.cpp:159
    xbmc#4 0x55bf354221c2 in CJobWorker::CJobWorker(CJobManager*) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:32
    xbmc#5 0x55bf354261d2 in CJobManager::StartWorkers(CJob::PRIORITY) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:288
    xbmc#6 0x55bf35425693 in CJobManager::AddJob(CJob*, IJobCallback*, CJob::PRIORITY) /home/dobo/kodi/xbmc/xbmc/utils/JobManager.cpp:247
    xbmc#7 0x55bf35d64c96 in Submit<CApplication::Initialize()::<lambda()> > /home/dobo/kodi/xbmc/xbmc/utils/JobManager.h:261
    xbmc#8 0x55bf35d3f094 in CApplication::Initialize() /home/dobo/kodi/xbmc/xbmc/application/Application.cpp:655
    xbmc#9 0x55bf356ae6b8 in XBMC_Run /home/dobo/kodi/xbmc/xbmc/platform/xbmc.cpp:43
    xbmc#10 0x55bf34321830 in main /home/dobo/kodi/xbmc/xbmc/platform/posix/main.cpp:71
    xbmc#11 0x7ff0e9c9a78f  (/usr/lib/libc.so.6+0x2378f)

SUMMARY: AddressSanitizer: heap-use-after-free /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
Shadow bytes around the buggy address:
  0x0c0e800153b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e800153c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e800153d0: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
  0x0c0e800153e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e800153f0: fa fa fa fa fa fa fa fa fa fa fd fd fd fd fd fd
=>0x0c0e80015400: fd fd fd fa fa fa fa fa[fd]fd fd fd fd fd fd fd
  0x0c0e80015410: fd fa fa fa fa fa fd fd fd fd fd fd fd fd fd fa
  0x0c0e80015420: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
  0x0c0e80015430: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x0c0e80015440: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 00
  0x0c0e80015450: 00 00 00 00 00 00 00 fa fa fa fa fa fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==34632==ABORTING
  • Loading branch information
dobo90 committed Nov 29, 2023
1 parent ae960b2 commit c386ff9
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 67 deletions.
5 changes: 5 additions & 0 deletions xbmc/GUIUserMessages.h
Expand Up @@ -143,3 +143,8 @@ constexpr const int GUI_MSG_PLAYBACK_AVSTARTED = GUI_MSG_USER + 44;
// Sent to notify system sleep/wake
constexpr const int GUI_MSG_SYSTEM_SLEEP = GUI_MSG_USER + 45;
constexpr const int GUI_MSG_SYSTEM_WAKE = GUI_MSG_USER + 46;

constexpr const int GUI_MSG_PLAYBACK_PAUSED = GUI_MSG_USER + 47;
constexpr const int GUI_MSG_PLAYBACK_RESUMED = GUI_MSG_USER + 48;
constexpr const int GUI_MSG_PLAYBACK_SEEKED = GUI_MSG_USER + 49;
constexpr const int GUI_MSG_PLAYBACK_SPEED_CHANGED = GUI_MSG_USER + 50;
93 changes: 91 additions & 2 deletions xbmc/application/Application.cpp
Expand Up @@ -45,6 +45,7 @@
#include "application/ApplicationStackHelper.h"
#include "application/ApplicationVolumeHandling.h"
#include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
#include "cores/DataCacheCore.h"
#include "cores/FFmpeg.h"
#include "cores/IPlayer.h"
#include "cores/playercorefactory/PlayerCoreFactory.h"
Expand Down Expand Up @@ -211,7 +212,9 @@ CApplication::CApplication(void)
m_Autorun(new CAutorun()),
#endif
m_pInertialScrollingHandler(new CInertialScrollingHandler()),
m_WaitingExternalCalls(0)
m_WaitingExternalCalls(0),
m_itemCurrentFile(std::make_shared<CFileItem>()),
m_playerEvent(true, true)
{
TiXmlBase::SetCondenseWhiteSpace(false);

Expand Down Expand Up @@ -2719,6 +2722,12 @@ bool CApplication::OnMessage(CGUIMessage& message)
// @TODO move this away to platform code
CDarwinUtils::SetScheduling(GetComponent<CApplicationPlayer>()->IsPlayingVideo());
#endif
m_itemCurrentFile =
std::make_shared<CFileItem>(*std::static_pointer_cast<CFileItem>(message.GetItem()));
m_playerEvent.Reset();

CServiceBroker::GetPVRManager().OnPlaybackStarted(*m_itemCurrentFile);

PLAYLIST::CPlayList playList = CServiceBroker::GetPlaylistPlayer().GetPlaylist(
CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist());

Expand Down Expand Up @@ -2860,16 +2869,32 @@ bool CApplication::OnMessage(CGUIMessage& message)
}

case GUI_MSG_PLAYBACK_STOPPED:
{
CServiceBroker::GetPVRManager().OnPlaybackStopped(*m_itemCurrentFile);

CVariant data(CVariant::VariantTypeObject);
data["end"] = false;
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnStop",
m_itemCurrentFile, data);

m_playerEvent.Set();
ResetCurrentItem();
PlaybackCleanup();
#ifdef HAS_PYTHON
CServiceBroker::GetXBPython().OnPlayBackStopped();
#endif
return true;
}

case GUI_MSG_PLAYBACK_ENDED:
{
CServiceBroker::GetPVRManager().OnPlaybackEnded(*m_itemCurrentFile);

CVariant data(CVariant::VariantTypeObject);
data["end"] = true;
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnStop",
m_itemCurrentFile, data);

m_playerEvent.Set();
const auto stackHelper = GetComponent<CApplicationStackHelper>();
if (stackHelper->IsPlayingRegularStack() && stackHelper->HasNextStackPartFileItem())
Expand Down Expand Up @@ -2897,21 +2922,85 @@ bool CApplication::OnMessage(CGUIMessage& message)
return true;

case GUI_MSG_PLAYBACK_AVSTARTED:
{
CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnAVStart",
m_itemCurrentFile, param);
m_playerEvent.Set();
#ifdef HAS_PYTHON
// informs python script currently running playback has started
// (does nothing if python is not loaded)
CServiceBroker::GetXBPython().OnAVStarted(*m_itemCurrentFile);
#endif
return true;
}

case GUI_MSG_PLAYBACK_AVCHANGE:
{
#ifdef HAS_PYTHON
// informs python script currently running playback has started
// (does nothing if python is not loaded)
CServiceBroker::GetXBPython().OnAVChange();
#endif
return true;
CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnAVChange",
m_itemCurrentFile, param);
return true;
}

case GUI_MSG_PLAYBACK_PAUSED:
{
CVariant param;
param["player"]["speed"] = 0;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnPause",
m_itemCurrentFile, param);
return true;
}

case GUI_MSG_PLAYBACK_RESUMED:
{
CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnResume",
m_itemCurrentFile, param);
return true;
}

case GUI_MSG_PLAYBACK_SEEKED:
{
CVariant param;
const int64_t iTime = message.GetParam1AsI64();
const int64_t seekOffset = message.GetParam2AsI64();
JSONRPC::CJSONUtils::MillisecondsToTimeObject(iTime, param["player"]["time"]);
JSONRPC::CJSONUtils::MillisecondsToTimeObject(seekOffset, param["player"]["seekoffset"]);
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
const auto& components = CServiceBroker::GetAppComponents();
const auto appPlayer = components.GetComponent<CApplicationPlayer>();
param["player"]["speed"] = static_cast<int>(appPlayer->GetPlaySpeed());
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnSeek",
m_itemCurrentFile, param);

CDataCacheCore::GetInstance().SeekFinished(static_cast<int>(seekOffset));

return true;
}

case GUI_MSG_PLAYBACK_SPEED_CHANGED:
{
CVariant param;
param["player"]["speed"] = message.GetParam1();
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnSpeedChanged",
m_itemCurrentFile, param);

return true;
}

case GUI_MSG_PLAYBACK_ERROR:
HELPERS::ShowOKDialogText(CVariant{16026}, CVariant{16027});
Expand Down
2 changes: 2 additions & 0 deletions xbmc/application/Application.h
Expand Up @@ -251,6 +251,8 @@ friend class CAppInboundProtocol;
unsigned int m_ProcessedExternalCalls = 0; /*!< counts calls which are processed during one "door open" cycle in FrameMove */
unsigned int m_ProcessedExternalDecay = 0; /*!< counts to close door after a few frames of no python activity */
int m_ExitCode{EXITCODE_QUIT};
std::shared_ptr<CFileItem> m_itemCurrentFile; //!< Currently playing file
CEvent m_playerEvent;
};

XBMC_GLOBAL_REF(CApplication,g_application);
Expand Down
75 changes: 14 additions & 61 deletions xbmc/application/ApplicationPlayerCallback.cpp
Expand Up @@ -16,7 +16,6 @@
#include "application/ApplicationComponents.h"
#include "application/ApplicationPlayer.h"
#include "application/ApplicationStackHelper.h"
#include "cores/DataCacheCore.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIMessage.h"
#include "guilib/GUIWindowManager.h"
Expand All @@ -25,10 +24,10 @@
#include "interfaces/json-rpc/JSONUtils.h"
#include "interfaces/python/XBPython.h"
#include "profiles/ProfileManager.h"
#include "pvr/PVRManager.h"
#include "settings/AdvancedSettings.h"
#include "settings/MediaSettings.h"
#include "settings/SettingsComponent.h"
#include "utils/JobManager.h"
#include "utils/SaveFileStateJob.h"
#include "utils/URIUtils.h"
#include "utils/log.h"
Expand All @@ -38,28 +37,21 @@
#include <memory>

CApplicationPlayerCallback::CApplicationPlayerCallback()
: m_itemCurrentFile(new CFileItem), m_playerEvent(true, true)
{
}

void CApplicationPlayerCallback::OnPlayBackEnded()
{
CLog::LogF(LOGDEBUG, "CApplicationPlayerCallback::OnPlayBackEnded");

CServiceBroker::GetPVRManager().OnPlaybackEnded(*m_itemCurrentFile);

CVariant data(CVariant::VariantTypeObject);
data["end"] = true;
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnStop",
m_itemCurrentFile, data);

CGUIMessage msg(GUI_MSG_PLAYBACK_ENDED, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file)
{
CLog::LogF(LOGDEBUG, "CApplication::OnPlayBackStarted");
std::shared_ptr<CFileItem> itemCurrentFile;

// check if VideoPlayer should set file item stream details from its current streams
const bool isBlu_dvd_image_or_stream = (URIUtils::IsBluray(file.GetPath()) || file.IsDVDFile() ||
Expand All @@ -78,10 +70,11 @@ void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file)

auto& components = CServiceBroker::GetAppComponents();
const auto stackHelper = components.GetComponent<CApplicationStackHelper>();

if (stackHelper->IsPlayingISOStack() || stackHelper->IsPlayingRegularStack())
m_itemCurrentFile = std::make_shared<CFileItem>(*stackHelper->GetRegisteredStack(file));
itemCurrentFile = std::make_shared<CFileItem>(*stackHelper->GetRegisteredStack(file));
else
m_itemCurrentFile = std::make_shared<CFileItem>(file);
itemCurrentFile = std::make_shared<CFileItem>(file);

/* When playing video pause any low priority jobs, they will be unpaused when playback stops.
* This should speed up player startup for files on internet filesystems (eg. webdav) and
Expand All @@ -92,12 +85,9 @@ void CApplicationPlayerCallback::OnPlayBackStarted(const CFileItem& file)
CServiceBroker::GetJobManager()->PauseJobs();
}

CServiceBroker::GetPVRManager().OnPlaybackStarted(*m_itemCurrentFile);
stackHelper->OnPlayBackStarted(file);

m_playerEvent.Reset();

CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0);
CGUIMessage msg(GUI_MSG_PLAYBACK_STARTED, 0, 0, 0, 0, itemCurrentFile);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

Expand Down Expand Up @@ -181,11 +171,8 @@ void CApplicationPlayerCallback::OnPlayBackPaused()
CServiceBroker::GetXBPython().OnPlayBackPaused();
#endif

CVariant param;
param["player"]["speed"] = 0;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnPause",
m_itemCurrentFile, param);
CGUIMessage msg(GUI_MSG_PLAYBACK_PAUSED, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CApplicationPlayerCallback::OnPlayBackResumed()
Expand All @@ -194,24 +181,14 @@ void CApplicationPlayerCallback::OnPlayBackResumed()
CServiceBroker::GetXBPython().OnPlayBackResumed();
#endif

CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnResume",
m_itemCurrentFile, param);
CGUIMessage msg(GUI_MSG_PLAYBACK_RESUMED, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CApplicationPlayerCallback::OnPlayBackStopped()
{
CLog::LogF(LOGDEBUG, "CApplication::OnPlayBackStopped");

CServiceBroker::GetPVRManager().OnPlaybackStopped(*m_itemCurrentFile);

CVariant data(CVariant::VariantTypeObject);
data["end"] = false;
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnStop",
m_itemCurrentFile, data);

CGUIMessage msg(GUI_MSG_PLAYBACK_STOPPED, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}
Expand Down Expand Up @@ -246,17 +223,8 @@ void CApplicationPlayerCallback::OnPlayBackSeek(int64_t iTime, int64_t seekOffse
static_cast<int>(seekOffset));
#endif

CVariant param;
JSONRPC::CJSONUtils::MillisecondsToTimeObject(iTime, param["player"]["time"]);
JSONRPC::CJSONUtils::MillisecondsToTimeObject(seekOffset, param["player"]["seekoffset"]);
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
const auto& components = CServiceBroker::GetAppComponents();
const auto appPlayer = components.GetComponent<CApplicationPlayer>();
param["player"]["speed"] = static_cast<int>(appPlayer->GetPlaySpeed());
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnSeek",
m_itemCurrentFile, param);

CDataCacheCore::GetInstance().SeekFinished(static_cast<int>(seekOffset));
CGUIMessage msg(GUI_MSG_PLAYBACK_SEEKED, 0, 0, iTime, seekOffset);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CApplicationPlayerCallback::OnPlayBackSeekChapter(int iChapter)
Expand All @@ -272,11 +240,8 @@ void CApplicationPlayerCallback::OnPlayBackSpeedChanged(int iSpeed)
CServiceBroker::GetXBPython().OnPlayBackSpeedChanged(iSpeed);
#endif

CVariant param;
param["player"]["speed"] = iSpeed;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnSpeedChanged",
m_itemCurrentFile, param);
CGUIMessage msg(GUI_MSG_PLAYBACK_SPEED_CHANGED, 0, 0, iSpeed);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CApplicationPlayerCallback::OnAVChange()
Expand All @@ -287,12 +252,6 @@ void CApplicationPlayerCallback::OnAVChange()

CGUIMessage msg(GUI_MSG_PLAYBACK_AVCHANGE, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);

CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnAVChange",
m_itemCurrentFile, param);
}

void CApplicationPlayerCallback::OnAVStarted(const CFileItem& file)
Expand All @@ -301,12 +260,6 @@ void CApplicationPlayerCallback::OnAVStarted(const CFileItem& file)

CGUIMessage msg(GUI_MSG_PLAYBACK_AVSTARTED, 0, 0);
CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);

CVariant param;
param["player"]["speed"] = 1;
param["player"]["playerid"] = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist();
CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Player, "OnAVStart",
m_itemCurrentFile, param);
}

void CApplicationPlayerCallback::RequestVideoSettings(const CFileItem& fileItem)
Expand Down
4 changes: 0 additions & 4 deletions xbmc/application/ApplicationPlayerCallback.h
Expand Up @@ -36,8 +36,4 @@ class CApplicationPlayerCallback : public IPlayerCallback
void OnAVStarted(const CFileItem& file) override;
void RequestVideoSettings(const CFileItem& fileItem) override;
void StoreVideoSettings(const CFileItem& fileItem, const CVideoSettings& vs) override;

protected:
std::shared_ptr<CFileItem> m_itemCurrentFile; //!< Currently playing file
CEvent m_playerEvent;
};

0 comments on commit c386ff9

Please sign in to comment.