Skip to content

Commit

Permalink
Sound no duration fix (#190)
Browse files Browse the repository at this point in the history
* Convert aac to m4a

* Copy before conversion

* Bump version

* Delete unused file

* Add doc
  • Loading branch information
ruskakimov authored Jul 4, 2021
1 parent 8c01666 commit 967b22b
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 20 deletions.
18 changes: 18 additions & 0 deletions lib/common/data/io/aac_to_m4a.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dart:io';
import 'package:path/path.dart' as p;

import 'package:flutter_ffmpeg/flutter_ffmpeg.dart';

/// Wraps raw AAC with M4A container.
/// Raw AAC doesn't support seeking, therefore it is unusable.
Future<void> aacToM4a(File inputAAC, File outputM4A) async {
assert(p.extension(inputAAC.path) == '.aac');
assert(p.extension(outputM4A.path) == '.m4a');

final command = '-i ${inputAAC.path} -codec: copy ${outputM4A.path}';
final code = await FlutterFFmpeg().execute(command);

if (code != 0) {
throw Exception('Could not convert AAC to M4A, error code: $code');
}
}
46 changes: 31 additions & 15 deletions lib/common/data/project/project.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mooltik/common/data/io/aac_to_m4a.dart';
import 'package:mooltik/common/data/io/delete_files_where.dart';
import 'package:mooltik/common/data/io/generate_image.dart';
import 'package:mooltik/common/data/project/composite_frame.dart';
Expand Down Expand Up @@ -270,40 +271,55 @@ class Project extends ChangeNotifier {

String _getFrameFilePath(int id) => p.join(directory.path, 'frame$id.png');

File _getSoundClipFile(int id) => File(_getSoundClipFilePath(id));

String _getSoundDirectoryPath() => p.join(directory.path, 'sounds');

String _getSoundClipFilePath(int id) =>
p.join(_getSoundDirectoryPath(), '$id.aac');

Future<File> getNewSoundClipFile() async =>
await _getSoundClipFile(DateTime.now().millisecondsSinceEpoch)
.create(recursive: true);

Future<void> loadSoundClipFromFile(File source) async {
if (_soundClips.isNotEmpty) {
_soundClips.clear();
}

final sourceExtension = p.extension(source.path);
final fileName = '${DateTime.now().millisecondsSinceEpoch}$sourceExtension';
final soundFile = await _addSoundFileToProjectDir(source);

final soundFile = File(p.join(_getSoundDirectoryPath(), fileName));
await soundFile.create(recursive: true);
await source.copy(soundFile.path);
final duration = await getSoundFileDuration(soundFile);
if (duration == null) {
throw Exception('Could not read duration from file.');
}

final soundClip = SoundClip(
file: soundFile,
startTime: Duration.zero,
duration: await getSoundFileDuration(soundFile),
duration: duration,
);

_soundClips.add(soundClip);

notifyListeners();
}

Future<File> _addSoundFileToProjectDir(File source) async {
final sourceExtension = p.extension(source.path);
final copiedFile = File(p.join(
_getSoundDirectoryPath(),
'${DateTime.now().millisecondsSinceEpoch}$sourceExtension',
));
await copiedFile.create(recursive: true);
await source.copy(copiedFile.path);

var output = copiedFile;

// Raw AAC cannot be seeked, source: https://github.com/ryanheise/just_audio/issues/333#issuecomment-792867877
if (sourceExtension == '.aac') {
output = File(p.join(
_getSoundDirectoryPath(),
'${DateTime.now().millisecondsSinceEpoch}.m4a',
));
await aacToM4a(copiedFile, output);
await copiedFile.delete();
}

return output;
}

// =========
// Metadata:
// =========
Expand Down
8 changes: 4 additions & 4 deletions lib/common/data/project/sound_clip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class SoundClip {
SoundClip({
required this.file,
required Duration startTime,
Duration? duration,
required Duration duration,
}) : _startTime = startTime,
_duration = duration;

Expand All @@ -17,10 +17,10 @@ class SoundClip {
Duration get startTime => _startTime;
Duration _startTime;

Duration get endTime => _startTime + _duration!;
Duration get endTime => _startTime + _duration;

Duration? get duration => _duration;
Duration? _duration;
Duration get duration => _duration;
Duration _duration;

factory SoundClip.fromJson(Map<String, dynamic> json, String soundDirPath) =>
SoundClip(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.11.5
version: 1.11.6

environment:
sdk: '>=2.12.0 <3.0.0'
Expand Down

0 comments on commit 967b22b

Please sign in to comment.