fix crash recovery: add new constructors to SndFileSource, AudioFileSource, add a new SourceFactory method and finally tweak

AudioDiskstream::use_pending_capture_data() to create both the required whole-file and the in-playlist regions
This commit is contained in:
Paul Davis 2014-06-10 10:07:04 -04:00
parent 74bc0c8468
commit b660bc8ae9
8 changed files with 131 additions and 14 deletions

View file

@ -93,6 +93,12 @@ protected:
/** Constructor to be called for existing in-session files */
AudioFileSource (Session&, const XMLNode&, bool must_exist = true);
/** Constructor to be called for crash recovery. Final argument is not
* used but exists to differentiate from the external-to-session
* constructor above.
*/
AudioFileSource (Session&, const std::string& path, Source::Flag flags, bool);
int init (const std::string& idstr, bool must_exist);
virtual void set_header_timeline_position () = 0;

View file

@ -38,7 +38,16 @@ class SndFileSource : public AudioFileSource {
SampleFormat samp_format, HeaderFormat hdr_format, framecnt_t rate,
Flag flags = SndFileSource::default_writable_flags);
/** Constructor to be called for existing in-session files */
/* Constructor to be called for recovering files being used for
* capture. They are in-session, they already exist, they should not
* be writable. They are an odd hybrid (from a constructor point of
* view) of the previous two constructors.
*/
SndFileSource (Session&, const std::string& path, int chn);
/** Constructor to be called for existing in-session files during
* session loading
*/
SndFileSource (Session&, const XMLNode&);
~SndFileSource ();

View file

@ -57,6 +57,9 @@ class SourceFactory {
bool destructive, framecnt_t rate, bool announce = true, bool async = false);
static boost::shared_ptr<Source> createForRecovery
(DataType type, Session&, const std::string& path, int chn);
static boost::shared_ptr<Source> createFromPlaylist
(DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks);

View file

@ -2181,11 +2181,16 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
continue;
}
/* XXX as of June 2014, we always record to mono
files. Since this Source is being created as part of
crash recovery, we know that we need the first
channel (the final argument to the SourceFactory
call below). If we ever support non-mono files for
capture, this will need rethinking.
*/
try {
fs = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (
DataType::AUDIO, _session,
prop->value(), false, _session.frame_rate()));
fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createForRecovery (DataType::AUDIO, _session, prop->value(), 0));
}
catch (failed_constructor& err) {
@ -2216,21 +2221,31 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
return -1;
}
boost::shared_ptr<AudioRegion> region;
try {
PropertyList plist;
boost::shared_ptr<AudioRegion> wf_region;
boost::shared_ptr<AudioRegion> region;
/* First create the whole file region */
PropertyList plist;
plist.add (Properties::start, 0);
plist.add (Properties::length, first_fs->length (first_fs->timeline_position()));
plist.add (Properties::name, region_name_from_path (first_fs->name(), true));
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
wf_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
region->set_automatic (true);
region->set_whole_file (true);
region->special_set_position (0);
wf_region->set_automatic (true);
wf_region->set_whole_file (true);
wf_region->special_set_position (position);
/* Now create a region that isn't the whole file for adding to
* the playlist */
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
_playlist->add_region (region, position);
}
catch (failed_constructor& err) {
@ -2241,7 +2256,6 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
return -1;
}
_playlist->add_region (region, position);
return 0;
}

View file

@ -115,6 +115,22 @@ AudioFileSource::AudioFileSource (Session& s, const string& path, const string&
}
}
/** Constructor used for existing internal-to-session files during crash
* recovery. File must exist
*/
AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags, bool /* ignored-exists-for-prototype differentiation */)
: Source (s, DataType::AUDIO, path, flags)
, AudioSource (s, path)
, FileSource (s, DataType::AUDIO, path, string(), flags)
{
/* note that origin remains empty */
if (init (_path, true)) {
throw failed_constructor ();
}
}
/** Constructor used for existing internal-to-session files via XML. File must exist. */
AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
: Source (s, node)

View file

@ -56,7 +56,7 @@ PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::
FileSource::FileSource (Session& session, DataType type, const string& path, const string& origin, Source::Flag flag)
: Source(session, type, path, flag)
, _path (path)
, _file_is_new (!origin.empty()) // origin empty => new file VS. origin !empty => new file
, _file_is_new (!origin.empty()) // if origin is left unspecified (empty string) then file must exist
, _channel (0)
, _origin (origin)
, _open (false)

View file

@ -183,6 +183,34 @@ SndFileSource::SndFileSource (Session& s, const string& path, const string& orig
}
}
/** Constructor to be called for recovering files being used for
* capture. They are in-session, they already exist, they should not
* be writable. They are an odd hybrid (from a constructor point of
* view) of the previous two constructors.
*/
SndFileSource::SndFileSource (Session& s, const string& path, int chn)
: Source (s, DataType::AUDIO, path, Flag (0))
/* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
, AudioFileSource (s, path, Flag (0))
, _descriptor (0)
, _broadcast_info (0)
, _capture_start (false)
, _capture_end (false)
, file_pos (0)
, xfade_buf (0)
{
_channel = chn;
init_sndfile ();
assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
existence_check ();
if (open()) {
throw failed_constructor ();
}
}
void
SndFileSource::init_sndfile ()
{
@ -256,6 +284,14 @@ SndFileSource::open ()
delete _broadcast_info;
_broadcast_info = 0;
_flags = Flag (_flags & ~Broadcast);
}
/* Set the broadcast flag if the BWF info is already there. We need
* this when recovering or using existing files.
*/
if (bwf_info_exists) {
_flags = Flag (_flags | Broadcast);
}
if (writable()) {

View file

@ -341,6 +341,39 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat
return boost::shared_ptr<Source> ();
}
boost::shared_ptr<Source>
SourceFactory::createForRecovery (DataType type, Session& s, const std::string& path, int chn)
{
/* this might throw failed_constructor(), which is OK */
if (type == DataType::AUDIO) {
Source* src = new SndFileSource (s, path, chn);
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
// boost_debug_shared_ptr_mark_interesting (src, "Source");
#endif
boost::shared_ptr<Source> ret (src);
if (setup_peakfile (ret, false)) {
return boost::shared_ptr<Source>();
}
// no analysis data - this is still basically a new file (we
// crashed while recording.
// always announce these files
SourceCreated (ret);
return ret;
} else if (type == DataType::MIDI) {
error << _("Recovery attempted on a MIDI file - not implemented") << endmsg;
}
return boost::shared_ptr<Source> ();
}
boost::shared_ptr<Source>
SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks)