Статьи

Как вы можете добавить пользовательские мелодии на свой Windows Phone 7 из своего приложения (без Marketplace)

Все мы знаем, что Windows Phone 7 не поддерживает изменения мелодии звонка (не по умолчанию). Это может немного расстроить людей, которым не нравится ни одна из 30 предварительно загруженных мелодий (хотя, вероятно, ее трудно найти). В этой статье я собираюсь показать вам, как можно загрузить собственную мелодию звонка на ваше устройство WP7. Если вас не интересует кодовая часть проблемы и подробные объяснения, связанные с ней, я бы порекомендовал зайти в блог Криса Уолши и сразу же загрузить установщик рингтона .

Первое, что вам нужно знать, это то, что этот метод не является официальным. Использование его в вашем приложении, скорее всего, приведет к отклонению приложения с Windows Phone Marketplace . Так что используйте это на свой страх и риск.

Самый простой способ — использовать библиотеку Microsoft.Phone.Media.Extended — ее можно скачать прямо с этого места . Я также покажу, как сделать то же самое с помощью отражения, чтобы вам не нужно было добавлять дополнительную зависимость, но это будет позже.

Прежде чем я начну кодировать, подготовьте кучу мелодий, которые вы хотите скопировать на телефон. Это должен быть файл WMA (Windows Media Audio) . Нет ограничений по битрейту . Я использовал Expression Encoder 4 для кодирования MP3-файла в WMA, начиная с 48 кбит / с и заканчивая 320 кбит / с, и загружал их на телефон — каждый из них воспроизводился правильно.

После добавления ссылки на Microsoft.Phone.Media.Extended вам нужно будет создать экземпляр класса RingtoneLibrary. Это синглтон, поэтому вам нужно использовать текущий экземпляр:

RingtoneLibrary lib = RingtoneLibrary.Instance;

ПРИМЕЧАНИЕ. Как указано клавиатурой P, «ID_CAP_RINGTONE_ADD» — это возможность, которая должна быть объявлена ​​в WMAppManifest.xml.

Этот класс имеет один метод, необходимый для выполнения операции — AddRingtone . Он принимает два параметра — экземпляр потока (содержимое рингтона) и строку (имя рингтона). Имя рингтона должно содержать расширение wma, чтобы быть зарегистрированным.

Например, вот как я могу назвать его для мелодии звонка, которую я хочу назвать Утром:

lib.AddRingtone(stream, "Morning.wma");

Расширение WMA не будет отображаться в списке мелодий звонка. Поток для файла WMA может быть получен множеством способов. Например, я могу скачать его:

WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.OpenReadAsync(new Uri("http://dennisdel.com/someFile.wma"));

Как только данные загружены:

void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
MemoryStream st = new MemoryStream();
byte[] buffer = new byte[1024];

int count;

while ((count = e.Result.Read(buffer, 0, buffer.Length)) > 0)
{
st.Write(buffer, 0, count);
}

byte[] b = st.ToArray();

MemoryStream s = new MemoryStream(b);

RingtoneLibrary lib = RingtoneLibrary.Instance;
lib.AddRingtone(s, "Morning.wma");
}

Вы можете быть удивлены — почему я здесь использую два экземпляра MemoryStream. По какой-то причине, когда я передаю экземпляр MemoryStream, который был создан на основе существующего потока (e.Result), дорожка не воспроизводится (хотя длина байтового массива остается неизменной). Когда MemoryStream создается непосредственно из байтового массива, звук правильно регистрируется и воспроизводится позже.

После этого я вижу зарегистрированный на устройстве рингтон:

Этот метод также работает на эмуляторе, и если у вас включена консоль отладки, вы увидите, как регистрируется процесс добавления рингтона.

Теперь давайте посмотрим на фрагмент кода, который будет делать то же самое без добавления дополнительной ссылки на DLL:

Assembly extendedAssembly = Assembly.Load("Microsoft.Phone.Media.Extended, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e");

Type ringtoneLib = extendedAssembly.GetType("Microsoft.Phone.RingtoneLibrary");
FieldInfo instanceF = ringtoneLib.GetField("Instance");

object instance = instanceF.GetValue(null);

MethodInfo m = ringtoneLib.GetMethod("AddRingtone");
m.Invoke(instance, new object[] { s, "main.wma" });

Вот и все — не так долго, как можно было ожидать. Учитывая, что я уже знал используемые типы и методы, довольно просто идти по пути Reflection. Единственное, что нужно помнить, это наличие синглтона, и для получения текущего экземпляра класса мне нужно получить значение поля Instance.