#c# #windows-phone-8 #audio-streaming
#c# #windows-phone-8 #потоковое аудио
Вопрос:
Я пришел к выводу, что упаковка всех этих аудиофайлов в xap была просто плохой идеей, поскольку теперь она выросла примерно до 60 Мб. Я бы хотел больше не упаковывать свои аудиофайлы в приложение, а использовать URL-адреса и загружать их в изолированное хранилище, когда пользователь нажимает звуковые кнопки. Я не уверен, как это сделать с моим приложением, поскольку мои кнопки не кодируются индивидуально. Они автоматически загружаются из модели представления в LongListSelectors. И воспроизведение в зависимости от того, какой из них нажат (data.filepath). Ниже я попытался использовать изолированное хранилище, но получаю ошибки.
ОБНОВЛЕН mainpage.cs:
public partial class MainPage : PhoneApplicationPage
{
public string FilePath { get; set; }
WebClient _webClient;
// Constructor
public MainPage()
{
InitializeComponent();
// Set the data context of the listbox control to the sample data
DataContext = App.ViewModel;
//webclient download
_webClient = new WebClient();
_webClient.OpenReadCompleted = (s1, e1) =>
{
if (e1.Error == null)
{
try
{
string fileName = FilePath.
Substring(FilePath.LastIndexOf("/") 1).Trim();
bool isSpaceAvailable =
IsSpaceIsAvailable(e1.Result.Length);
if (isSpaceAvailable)
{
// Save mp3 to Isolated Storage
using (var isfs = new IsolatedStorageFileStream(
fileName, FileMode.CreateNew,
IsolatedStorageFile.GetUserStoreForApplication()))
{
long fileLen = e1.Result.Length;
byte[] b = new byte[fileLen];
e1.Result.Read(b, 0, b.Length);
isfs.Write(b, 0, b.Length);
isfs.Flush();
}
}
else
{
MessageBox.Show("Not enough to save space available to download mp3.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show(e1.Error.Message);
}
};
}
// Check to make sure there are enough space available on the phone
// in order to save the image that we are downloading on to the phone
private bool IsSpaceIsAvailable(long spaceReq)
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
long spaceAvail = store.AvailableFreeSpace;
if (spaceReq > spaceAvail)
{
return false;
}
return true;
}
}
// Sample code to localize the ApplicationBar
// Load data for the ViewModel Items
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
}
private void LongListSelector_SelectionChanged(
object sender, SelectionChangedEventArgs e)
{
LongListSelector selector = sender as LongListSelector;
// verifying our sender is actually a LongListSelector
if (selector == null)
return;
SoundData data = selector.SelectedItem as SoundData;
// verifying our sender is actually SoundData
if (data == null)
return;
if (File.Exists(data.FilePath))
{
AudioPlayer.Source = new Uri(
data.FilePath,
UriKind.RelativeOrAbsolute);
}
else
{
using (var storageFolder =
IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = new IsolatedStorageFileStream(
data.FilePath, FileMode.Open, storageFolder))
{
AudioPlayer.SetSource(stream);
}
}
}
selector.SelectedItem = null;
Вот немного моей модели SoundModel. Я оставил один пример того, как он настроен сейчас с локальным хранилищем, которое работает. Другой — как мне нравится использовать URL-адрес.
private SoundGroup CreateGamesGroup()
{
SoundGroup data = new SoundGroup();
data.Title = "Games";
string basePath = "assets/audio/Games/";
data.Items.Add(new SoundData
{
Title = "Gauntlet Exit",
FilePath = basePath "GauntletExit.mp3",
Groups = "VideoGames"
});
data.Items.Add(new SoundData
{
Title = "Gauntlet Exit",
FilePath =
"http://k007.kiwi6.com/hotlink/23lenhzr3h/GauntletExit.mp3",
Groups="VideoGames"
});
Поскольку Mainpage.cs ссылается на модель SoundData, я добавлю это и здесь:
public class SoundData : ViewModelBase
{
public string Title { get; set; }
public string FilePath { get; set; }
public string Items { get; set; }
public string Groups { get; set; }
public RelayCommand<string> SaveSoundAsRingtone { get; set; }
private void ExecuteSaveSoundAsRingtone(string soundPath)
{
App.Current.RootVisual.Dispatcher.BeginInvoke(() =>
{
SaveRingtoneTask task = new SaveRingtoneTask();
task.Source = new Uri("appdata:/" this.FilePath);
task.DisplayName = this.Title;
task.Show();
}
);
}
public SoundData()
{
SaveSoundAsRingtone =
new RelayCommand<string>(ExecuteSaveSoundAsRingtone);
}
В настоящее время URL-адрес работает не так, как я ожидал. Я получаю эти ошибки:
Исключение первого случая типа ‘System.IO.IsolatedStorage.Исключение IsolatedStorageException’ произошло в mscorlib.ni.dll Исключение типа ‘System.IO.IsolatedStorage.Исключение IsolatedStorageException’ произошло в mscorlib.ni.dll но не был обработан в пользовательском коде Дополнительная информация: Операция не разрешена для IsolatedStorageFileStream.
Комментарии:
1. Я вижу, вы обновили свой вопрос. Обновленный ответ соответствующим образом.
Ответ №1:
Не уверен, что это основная причина ваших проблем, но вам нужно использовать appdata:/
для файлов, включенных в XAP, в противном случае используйте isostore:/
Если у вас есть элементы, привязанные к LongListSelector с помощью открытого свойства, вы можете назначить команду своим элементам и обрабатывать «клики» в вашей viewmodel.
Допустим, у вас есть следующее в вашей виртуальной машине:
public ObservableCollection<SoundData> AudioFiles { get; set; }
public ICommand PlayCommand { get; set; }
Тогда связанный XAML будет выглядеть примерно так:
<phone:LongListSelector
x:Name="AudioFilesList"
ItemsSource="{Binding AudioFiles}"
SelectedItem="{Binding SoundData}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<command:EventToCommand
Command="{Binding PlayCommand}"
CommandParameter="{Binding Path=SelectedItem,
ElementName=AudioFilesList}"
PassEventArgsToCommand="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="2"
BorderBrush="{StaticResource PhoneForegroundBrush}"
Height="80">
<TextBlock
Text="{Binding FilePath}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource PhoneTextNormalStyle}" />
</Border>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Важная часть выше — ItemsSource, SelectedItem и привязка PlayCommand для LongListSelector .
Я создал небольшой пример проекта @ Git, надеюсь, это поможет вам разобраться https://github.com/mikkoviitala/any-ringtone
Он получает несколько mp3-файлов по http, сохраняет файлы в IsoStore, а затем отображает элементы в LongListSelector. Нажатие на элемент списка запускает команду, которая выполняет Ringtonetask.